diff --git a/.gitignore b/.gitignore index 7f8c4aca48..0e3d3e80e9 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,4 @@ packages/devtools/client/public/discovery/index.html .context .claude .ghfs +.omo diff --git a/package.json b/package.json index 0fa4574621..6939ba16e9 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "test:e2e:all": "pnpm test:e2e:prebuild && playwright test --config tests/e2e/playwright.config.ts", "test:e2e:dev": "PW_PROJECT='*:dev' playwright test --config tests/e2e/playwright.config.ts", "test:e2e:built": "pnpm test:e2e:prebuild && PW_PROJECT='*:built' playwright test --config tests/e2e/playwright.config.ts", - "test:e2e:prebuild": "pnpm -C playgrounds/empty exec nuxt build && pnpm -C playgrounds/tab-pinia exec nuxt build && pnpm -C playgrounds/tab-seo exec nuxt build", + "test:e2e:prebuild": "pnpm -C playgrounds/empty exec nuxt build && pnpm -C playgrounds/spa exec nuxt build && pnpm -C playgrounds/tab-pinia exec nuxt build && pnpm -C playgrounds/tab-seo exec nuxt build", "test:e2e:ui": "playwright test --config tests/e2e/playwright.config.ts --ui", "docs": "nuxi dev docs", "docs:build": "CI=true nuxi generate docs", diff --git a/packages/devtools/src/module-main.ts b/packages/devtools/src/module-main.ts index 642496e7a3..496cf2008a 100644 --- a/packages/devtools/src/module-main.ts +++ b/packages/devtools/src/module-main.ts @@ -80,6 +80,11 @@ export async function enableModule(options: ModuleOptions, nuxt: Nuxt) { // Deferred: will be set when Vite DevTools plugin setup runs let connectDevToolsKit: ((ctx: any) => void) | undefined + // Do NOT pass `{ server: false }` here: under Nuxt 5 / Vite 8 the kit wraps + // the plugin in an `applyToEnvironment` shell that strips the `devtools` + // property, so `@vitejs/devtools` silently drops the dock entry. The + // original client-vs-server RPC race is already handled by the guard inside + // `connectDevToolsKit` (`if (devtoolsKitCtx) return`). addVitePlugin(defineViteDevToolsPlugin({ name: 'nuxt:devtools', devtools: { @@ -96,7 +101,7 @@ export async function enableModule(options: ModuleOptions, nuxt: Nuxt) { connectDevToolsKit?.(ctx) }, }, - }), { server: false }) + })) addPlugin({ src: join(runtimeDir, 'plugins/vite-devtools.client'), mode: 'client', diff --git a/playgrounds/spa/.npmrc b/playgrounds/spa/.npmrc new file mode 100644 index 0000000000..cf04042455 --- /dev/null +++ b/playgrounds/spa/.npmrc @@ -0,0 +1,2 @@ +shamefully-hoist=true +strict-peer-dependencies=false diff --git a/playgrounds/spa/app.vue b/playgrounds/spa/app.vue new file mode 100644 index 0000000000..c4be295cda --- /dev/null +++ b/playgrounds/spa/app.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/playgrounds/spa/nuxt.config.ts b/playgrounds/spa/nuxt.config.ts new file mode 100644 index 0000000000..7b931371d3 --- /dev/null +++ b/playgrounds/spa/nuxt.config.ts @@ -0,0 +1,23 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +const devtoolsModule = process.env.NUXT_DEVTOOLS_LOCAL ? '../../local' : '@nuxt/devtools' + +// Regression playground for the dock-missing bug. With `ssr: false` AND +// `experimental.viteEnvironmentApi: true`, `@nuxt/kit`'s `addVitePlugin` +// takes the `applyToEnvironment` wrapper branch (`config.environments` is +// always populated). The wrapper plugin object lacks a `devtools` property, +// so `@vitejs/devtools`'s `"devtools" in plugin` filter silently drops it +// and the Nuxt DevTools dock entry never registers. This mirrors the Nuxt 5 +// vite-builder code path the bug was originally reported against. +export default defineNuxtConfig({ + modules: [ + devtoolsModule, + ], + + ssr: false, + + experimental: { + viteEnvironmentApi: true, + }, + + compatibilityDate: '2024-09-19', +}) diff --git a/playgrounds/spa/package.json b/playgrounds/spa/package.json new file mode 100644 index 0000000000..159437a3cf --- /dev/null +++ b/playgrounds/spa/package.json @@ -0,0 +1,23 @@ +{ + "name": "spa", + "version": "4.0.0-alpha.6", + "private": true, + "main": "nuxt.config.ts", + "files": [ + "app.vue", + "components", + "nuxt.config.ts", + "pages", + "public" + ], + "scripts": { + "play:build": "nuxt build", + "play:dev": "nuxt dev", + "play:generate": "nuxt generate", + "play:preview": "nuxt preview" + }, + "devDependencies": { + "@types/node": "catalog:types", + "nuxt": "catalog:buildtools" + } +} diff --git a/playgrounds/spa/public/empty.txt b/playgrounds/spa/public/empty.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/playgrounds/spa/tsconfig.json b/playgrounds/spa/tsconfig.json new file mode 100644 index 0000000000..a746f2a70c --- /dev/null +++ b/playgrounds/spa/tsconfig.json @@ -0,0 +1,4 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "extends": "./.nuxt/tsconfig.json" +} diff --git a/tests/e2e/playwright.config.ts b/tests/e2e/playwright.config.ts index dc5ac827ce..f68c4ea289 100644 --- a/tests/e2e/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -5,7 +5,7 @@ import { matchesProjectFilter } from './shared/glob' const REPO_ROOT = fileURLToPath(new URL('../..', import.meta.url)) -const PLAYGROUNDS = ['empty', 'tab-pinia', 'tab-seo'] as const +const PLAYGROUNDS = ['empty', 'spa', 'tab-pinia', 'tab-seo'] as const const MODES = ['dev', 'built'] as const type Mode = typeof MODES[number]