From e6771922c2f085bc8d98761e494563fe0efe1516 Mon Sep 17 00:00:00 2001 From: "Anthony Fu (via agent)" Date: Fri, 24 Jul 2026 06:56:43 +0000 Subject: [PATCH 1/6] feat(devtools)!: make embedded dock the only client mode The DevTools client now always renders as the shared-frame anchor inside the Vite DevTools dock, so the standalone app shell is gone: SideNav, split view, the docking panel, the first-visit welcome page and their settings entries are removed, along with the `?embed=1` detection flag they were gated behind. Drop the Vitest integration (`@nuxt/test-utils/module` + `@vitest/ui`) now that Vite+ ships its own, and hide the redundant `nuxt:devtools` anchor dock button once its per-tab members have bootstrapped. --- packages/devtools-kit/src/_types/options.ts | 3 - packages/devtools/client/app.vue | 45 ++--- .../client/components/DockingPanel.vue | 44 ----- .../devtools/client/components/SideNav.vue | 170 ------------------ .../client/components/SideNavItem.vue | 81 --------- .../client/components/SplitScreen.vue | 112 ------------ .../devtools/client/components/TabsGrid.vue | 26 --- .../client/components/TimelineView.vue | 1 - packages/devtools/client/composables/embed.ts | 32 ---- .../devtools/client/composables/frame-nav.ts | 11 +- .../devtools/client/composables/state-tabs.ts | 34 +--- .../devtools/client/composables/storage.ts | 11 +- .../client/middleware/route.global.ts | 17 +- packages/devtools/client/nuxt.config.ts | 1 - packages/devtools/client/pages/index.vue | 49 ----- .../client/pages/modules/overview.vue | 12 +- packages/devtools/client/pages/settings.vue | 141 --------------- packages/devtools/package.json | 2 - packages/devtools/src/constant.ts | 3 - packages/devtools/src/module-main.ts | 11 +- .../src/runtime/plugins/view/client.ts | 33 ++++ pnpm-lock.yaml | 110 ++---------- pnpm-workspace.yaml | 1 - tests/e2e/fixtures/devtools.ts | 17 +- tests/e2e/specs/iframe.spec.ts | 8 +- tests/e2e/specs/nuxt-group.spec.ts | 10 ++ 26 files changed, 89 insertions(+), 896 deletions(-) delete mode 100644 packages/devtools/client/components/DockingPanel.vue delete mode 100644 packages/devtools/client/components/SideNav.vue delete mode 100644 packages/devtools/client/components/SideNavItem.vue delete mode 100644 packages/devtools/client/components/SplitScreen.vue delete mode 100644 packages/devtools/client/components/TabsGrid.vue delete mode 100644 packages/devtools/client/composables/embed.ts delete mode 100644 packages/devtools/client/pages/index.vue diff --git a/packages/devtools-kit/src/_types/options.ts b/packages/devtools-kit/src/_types/options.ts index 4508b5ea1d..f56884ff6b 100644 --- a/packages/devtools-kit/src/_types/options.ts +++ b/packages/devtools-kit/src/_types/options.ts @@ -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 diff --git a/packages/devtools/client/app.vue b/packages/devtools/client/app.vue index a446a113c9..76da88ba85 100644 --- a/packages/devtools/client/app.vue +++ b/packages/devtools/client/app.vue @@ -1,15 +1,12 @@ - - diff --git a/packages/devtools/client/components/SideNav.vue b/packages/devtools/client/components/SideNav.vue deleted file mode 100644 index dba28afb15..0000000000 --- a/packages/devtools/client/components/SideNav.vue +++ /dev/null @@ -1,170 +0,0 @@ - - - diff --git a/packages/devtools/client/components/SideNavItem.vue b/packages/devtools/client/components/SideNavItem.vue deleted file mode 100644 index d4a8594c87..0000000000 --- a/packages/devtools/client/components/SideNavItem.vue +++ /dev/null @@ -1,81 +0,0 @@ - - - diff --git a/packages/devtools/client/components/SplitScreen.vue b/packages/devtools/client/components/SplitScreen.vue deleted file mode 100644 index f43a9c0cd1..0000000000 --- a/packages/devtools/client/components/SplitScreen.vue +++ /dev/null @@ -1,112 +0,0 @@ - - - diff --git a/packages/devtools/client/components/TabsGrid.vue b/packages/devtools/client/components/TabsGrid.vue deleted file mode 100644 index 31eee8b154..0000000000 --- a/packages/devtools/client/components/TabsGrid.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/packages/devtools/client/components/TimelineView.vue b/packages/devtools/client/components/TimelineView.vue index 9b09f04330..1c4c296760 100644 --- a/packages/devtools/client/components/TimelineView.vue +++ b/packages/devtools/client/components/TimelineView.vue @@ -101,7 +101,6 @@ function toggleView() { :model-value="!!selected" auto-close transition="bottom" - left="#nuxt-devtools-side-nav" @close="selected = undefined" >
diff --git a/packages/devtools/client/composables/embed.ts b/packages/devtools/client/composables/embed.ts deleted file mode 100644 index f307e9d46d..0000000000 --- a/packages/devtools/client/composables/embed.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { ref } from 'vue' - -const STORAGE_KEY = 'nuxt-devtools-embedded' - -/** - * "Embedded" mode: the client is loaded as the shared-frame **anchor** inside a - * Vite DevTools dock iframe (`?embed=1`). In this mode the app shell — SideNav - * and split pane — is hidden so the iframe shows only the current tab, and the - * `devframe:frame-nav` shim drives tab navigation from the dock instead. - * - * The flag is latched into `sessionStorage` (isolated per iframe) so it - * survives soft navigation that drops the query and any reloads. - */ -function detect(): boolean { - if (typeof window === 'undefined') - return false - try { - if (window.sessionStorage.getItem(STORAGE_KEY) === '1') - return true - } - catch {} - const embedded = new URLSearchParams(window.location.search).get('embed') === '1' - if (embedded) { - try { - window.sessionStorage.setItem(STORAGE_KEY, '1') - } - catch {} - } - return embedded -} - -export const isEmbedded = ref(detect()) diff --git a/packages/devtools/client/composables/frame-nav.ts b/packages/devtools/client/composables/frame-nav.ts index b6b3969d10..cbc224afcc 100644 --- a/packages/devtools/client/composables/frame-nav.ts +++ b/packages/devtools/client/composables/frame-nav.ts @@ -10,10 +10,9 @@ import { useEnabledTabs } from '~/composables/state-tabs' // iframe/reload is needed. The shim is transport-only: it takes no hub/RPC // dependency, just `postMessage`. // -// The announced set comes from `useEnabledTabs()` — the same conditional list -// the SideNav used — so a tab's `show()` condition, hidden/pinned settings and -// experimental gating decide whether its dock appears, and the manifest is -// re-announced whenever that set changes. +// The announced set comes from `useEnabledTabs()` — so a tab's `show()` +// condition, hidden/pinned settings and experimental gating decide whether its +// dock appears, and the manifest is re-announced whenever that set changes. const CHANNEL = 'devframe:frame-nav' const VERSION = 1 // Must match the anchor's `frameId` registered in `module-main.ts`. @@ -78,8 +77,8 @@ export function setupFrameNav(): void { title: tab.title ?? tab.name, icon: normalizeIcon(tab.icon), defaultOrder: 'defaultOrder' in tab ? tab.defaultOrder : undefined, - // Mirror `getCategorizedTabs`: an uncategorised tab belongs to `app`, so - // the `Nuxt` group's `categoryOrder` weights apply to it. + // An uncategorised tab belongs to `app`, so the `Nuxt` group's + // `categoryOrder` weights apply to it. category: tab.category || 'app', navTarget: { path: tabPath(tab) }, })), diff --git a/packages/devtools/client/composables/state-tabs.ts b/packages/devtools/client/composables/state-tabs.ts index aff769ff20..3d5c63be08 100644 --- a/packages/devtools/client/composables/state-tabs.ts +++ b/packages/devtools/client/composables/state-tabs.ts @@ -1,7 +1,6 @@ -import type { ComputedRef, MaybeRef } from 'vue' -import type { CategorizedTabs, ModuleBuiltinTab, ModuleCustomTab, RouteInfo, TabCategory } from '../../src/types' +import type { ModuleBuiltinTab, ModuleCustomTab, RouteInfo, TabCategory } from '../../src/types' import { objectPick } from '@antfu/utils' -import { computed, toValue, unref } from 'vue' +import { computed, toValue } from 'vue' import { useRouter } from '#app/composables/router' import { useClientRouter } from './client' import { useCustomTabs, useServerPages } from './state' @@ -64,35 +63,6 @@ function getCategorizedRecord(): Record): ComputedRef { - const { - pinnedTabs, - } = useDevToolsOptions('ui') - - return computed(() => { - const categories = getCategorizedRecord() - for (const tab of unref(tabs)) { - let category = (tab.category || 'app') - if (pinnedTabs.value.includes(tab.name)) - category = 'pinned' - if (!categories[category]) - console.warn(`Unknown tab category: ${category}`) - else - categories[category].push(tab) - } - - for (const key of Object.keys(categories)) { - if (categories[key as TabCategory].length === 0) - delete categories[key as TabCategory] - } - - if (categories.pinned?.length) - categories.pinned.sort((a, b) => pinnedTabs.value.indexOf(a.name) - pinnedTabs.value.indexOf(b.name)) - - return Object.entries(categories) as CategorizedTabs - }) -} - export function useEnabledTabs() { const tabs = useAllTabs() const settings = useDevToolsOptions('ui') diff --git a/packages/devtools/client/composables/storage.ts b/packages/devtools/client/composables/storage.ts index 9b335d7e77..745f8b9a28 100644 --- a/packages/devtools/client/composables/storage.ts +++ b/packages/devtools/client/composables/storage.ts @@ -1,14 +1,5 @@ import type { DevToolsFrameState } from '~~/../src/types' -import { useLocalStorage, useWindowSize } from '@vueuse/core' -import { computed } from 'vue' - -export const isFirstVisit = useLocalStorage('nuxt-devtools-first-visit', true) - -const windowSize = useWindowSize() - -export const splitScreenAvailable = computed(() => windowSize.width.value > 1080) -export const splitScreenEnabled = useLocalStorage('nuxt-devtools-split-screen', false) -export const splitScreenView = useLocalStorage('nuxt-devtools-split-screen-view', 'overview') +import { useLocalStorage } from '@vueuse/core' const devToolsFrameState = useLocalStorage('nuxt-devtools-frame-state', {} as any, { listenToStorageChanges: true }) const devToolsPanelsState = useLocalStorage>('nuxt-devtools-panels-state', {} as any, { listenToStorageChanges: false }) diff --git a/packages/devtools/client/middleware/route.global.ts b/packages/devtools/client/middleware/route.global.ts index a57a187a1e..998ea6767d 100644 --- a/packages/devtools/client/middleware/route.global.ts +++ b/packages/devtools/client/middleware/route.global.ts @@ -1,21 +1,8 @@ import { defineNuxtRouteMiddleware, navigateTo } from '#imports' -import { isEmbedded } from '~/composables/embed' -import { isFirstVisit } from '~/composables/storage' export default defineNuxtRouteMiddleware((to) => { - // Embedded anchor: skip the first-visit welcome; land on a real tab so the + // The client is always the shared-frame anchor: land on a real tab so the // frame-nav shim has something to report as the current view. - if (isEmbedded.value) { - if (to.path === '/') - return navigateTo('/modules/overview') - return - } - - if (isFirstVisit.value) { - if (to.path !== '/') - return navigateTo('/') - } - else if (to.path === '/') { + if (to.path === '/') return navigateTo('/modules/overview') - } }) diff --git a/packages/devtools/client/nuxt.config.ts b/packages/devtools/client/nuxt.config.ts index 874e646d81..5284d8bba3 100644 --- a/packages/devtools/client/nuxt.config.ts +++ b/packages/devtools/client/nuxt.config.ts @@ -17,7 +17,6 @@ const packageBundles = { export default defineNuxtConfig({ modules: [ - '@nuxt/test-utils/module', '~/modules/markdown', DevToolsUiKit, DevTools, diff --git a/packages/devtools/client/pages/index.vue b/packages/devtools/client/pages/index.vue deleted file mode 100644 index e5ebd6f490..0000000000 --- a/packages/devtools/client/pages/index.vue +++ /dev/null @@ -1,49 +0,0 @@ - - - diff --git a/packages/devtools/client/pages/modules/overview.vue b/packages/devtools/client/pages/modules/overview.vue index a6278352f1..a9b07467e7 100644 --- a/packages/devtools/client/pages/modules/overview.vue +++ b/packages/devtools/client/pages/modules/overview.vue @@ -1,13 +1,11 @@