Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { existsSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import antfu from '@antfu/eslint-config'
import { extend } from 'eslint-flat-config-utils'

export default antfu(
// The client Nuxt app's generated flat config only exists once the app has been
// prepared (`pnpm dev:prepare`/`pnpm build`). Skip it gracefully when it hasn't
// been generated yet (e.g. a fresh `pnpm install && pnpm lint` in CI) so linting
// doesn't hard-crash on the missing import.
const clientConfigUrl = new URL('./packages/devtools/client/.nuxt/eslint.config.mjs', import.meta.url)
const hasClientConfig = existsSync(fileURLToPath(clientConfigUrl))

const config = antfu(
{
formatters: true,
unocss: true,
Expand All @@ -22,12 +31,37 @@ export default antfu(
},
},
)
.append(
.removeRules(
'vue/no-multiple-template-root',
)

// `FlatConfigComposer.append()` mutates the composer in place (and returns it),
// so the export stays a `const`.
if (hasClientConfig) {
config.append(
extend(
import('./packages/devtools/client/.nuxt/eslint.config.mjs').then(mod => mod.default()),
import(clientConfigUrl.href).then(mod => mod.default()),
'packages/devtools/client',
),
)
.removeRules(
'vue/no-multiple-template-root',
}
else {
// Before the client app is prepared, its generated flat config (which wires up
// `eslint-plugin-unimport`) is absent, so the `unimport/auto-insert` rule the
// client's inline `eslint-disable` directives reference is undefined. Register
// the plugin so those directives resolve and linting doesn't error.
config.append(
import('eslint-plugin-unimport').then(mod => ({
name: 'nuxt-devtools/client/unimport-fallback',
files: ['packages/devtools/client/**/*.{ts,vue}'],
plugins: { unimport: mod.default ?? mod },
rules: { 'unimport/auto-insert': 'off' },
// The rule is off in this fallback, so the client's inline disable
// directives read as "unused"; don't report (or auto-fix away) them —
// they are needed once the client app is prepared and the rule is active.
linterOptions: { reportUnusedDisableDirectives: 'off' },
})),
)
}

export default config
3 changes: 0 additions & 3 deletions packages/devtools-kit/src/_types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,10 @@ export interface NuxtDevToolsOptions {
componentsView: 'list' | 'graph'
hiddenTabCategories: string[]
hiddenTabs: string[]
interactionCloseOnOutsideClick: boolean
pinnedTabs: string[]
scale: number
showExperimentalFeatures: boolean
showHelpButtons: boolean
sidebarExpanded: boolean
sidebarScrollable: boolean
}
serverRoutes: {
selectedRoute: ServerRouteInfo | null
Expand Down
45 changes: 10 additions & 35 deletions packages/devtools/client/app.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
<script setup lang="ts">
import { useEventListener, useEyeDropper } from '@vueuse/core'
import { computed, onMounted, ref, watch, watchEffect } from 'vue'
import { useRoute } from '#app/composables/router'
import { useHead } from '#imports'
import { getColorMode, showConnectionWarning, useClient, useInjectionClient } from '~/composables/client'
import { useCopy } from '~/composables/editor'
import { isEmbedded } from '~/composables/embed'
import { setupFrameNav } from '~/composables/frame-nav'
import { WS_DEBOUNCE_TIME } from '~/composables/rpc'
import { registerCommands } from '~/composables/state-commands'
import { splitScreenAvailable, splitScreenEnabled } from '~/composables/storage'
import { wsConnectedOnce } from './composables/rpc'
import { useSchemaInput } from './composables/state-schema'
import { useDevToolsOptions } from './composables/storage-options'
Expand Down Expand Up @@ -43,12 +40,7 @@ useHead({
setupClientRPC()

const client = useClient()
const route = useRoute()
const colorMode = getColorMode()
// When embedded as the shared-frame anchor (`?embed=1`), hide the app shell
// (SideNav + split pane) so the iframe shows only the current tab; the dock's
// per-tab members drive navigation via the frame-nav shim.
const isUtilityView = computed(() => isEmbedded.value || route.path.startsWith('/__') || route.path === '/')
const waiting = computed(() => !client.value && !showConnectionWarning.value)
const showDisconnectIndicator = ref(false)

Expand Down Expand Up @@ -88,14 +80,14 @@ useEventListener('keydown', (e) => {
}
})

const { scale, sidebarExpanded } = useDevToolsOptions('ui')
const { scale } = useDevToolsOptions('ui')
const dataSchema = useSchemaInput()

onMounted(async () => {
// As the shared-frame anchor, announce our tabs to the dock and answer
// soft-navigation over postMessage.
if (isEmbedded.value)
setupFrameNav()
// Nuxt DevTools always renders as the shared-frame anchor inside the Vite
// DevTools dock: announce our tabs to the dock and answer soft-navigation
// over postMessage.
setupFrameNav()

const injectClient = useInjectionClient()
watchEffect(() => {
Expand All @@ -111,16 +103,6 @@ const copy = useCopy()
const eyeDropper = useEyeDropper({})

registerCommands(() => [
...(splitScreenAvailable.value
? [{
id: 'action:split-screen',
title: `${splitScreenEnabled.value ? 'Close' : 'Open'} Split Screen`,
icon: 'i-carbon-split-screen',
action: () => {
splitScreenEnabled.value = !splitScreenEnabled.value
},
}]
: []),
...(eyeDropper.isSupported.value
? [{
id: 'action:eye-dropper',
Expand Down Expand Up @@ -158,21 +140,14 @@ registerCommands(() => [
</NLoading>
<div
v-else
:class="isEmbedded ? 'grid grid-cols-[1fr]' : isUtilityView ? 'flex' : sidebarExpanded ? 'grid grid-cols-[250px_1fr]' : 'grid grid-cols-[50px_1fr]'"
id="nuxt-devtools-app"
class="grid grid-cols-[1fr]"
h-full h-screen of-hidden rounded-xl bg-base font-sans
>
<SideNav v-show="!isUtilityView" of-x-hidden of-y-auto />
<!-- Single-tab view: the shared-frame anchor mounts the current tab
directly; the Vite DevTools dock provides navigation between tabs. -->
<NuxtLayout>
<!-- Embedded single-tab view: mount the tab content directly, no split pane -->
<NuxtPage v-if="isEmbedded" />
<NSplitPane v-else storage-key="devtools:split-screen-mode" :min-size="20">
<template #left>
<NuxtPage />
</template>
<template v-if="!isUtilityView && splitScreenEnabled && splitScreenAvailable" #right>
<SplitScreen />
</template>
</NSplitPane>
<NuxtPage />
</NuxtLayout>
<CommandPalette />
</div>
Expand Down
44 changes: 0 additions & 44 deletions packages/devtools/client/components/DockingPanel.vue

This file was deleted.

170 changes: 0 additions & 170 deletions packages/devtools/client/components/SideNav.vue

This file was deleted.

Loading
Loading