From e8f85d84962a10e7571a6524b5744134ee4ea717 Mon Sep 17 00:00:00 2001 From: MK Date: Sat, 14 Mar 2026 16:20:28 +0800 Subject: [PATCH] fix(test): resolve ws CJS named export error with cloudflare preset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes #831 When Nuxt's cloudflare preset is active, vitest passes `--conditions browser` to worker processes. This caused `ws` to resolve to its browser stub (`ws/browser.js`) instead of the ESM wrapper (`ws/wrapper.mjs`), because the test package's `node` export condition loaded `index-node.js` which imports `@vitest/browser/index.js` → `ws`. Fix by adding a `browser` export condition before `node` in the test package's main export. When `--conditions browser` is active, `browser` matches first and resolves to `dist/index.js` (which doesn't pull in `@vitest/browser`), avoiding the ws resolution issue. Also fix ecosystem-ci `patch-project.ts` to apply pnpm overrides for projects that already use Vite+ (previously skipped by `vp migrate`), and add the reproduction repo as an e2e test case. --- .github/workflows/e2e-test.yml | 4 ++++ ecosystem-ci/patch-project.ts | 12 ++++++++++++ ecosystem-ci/repo.json | 6 ++++++ packages/test/build.ts | 9 +++++++++ packages/test/package.json | 1 + 5 files changed, 32 insertions(+) diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 4b5a89ada9..b8fa95cf73 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -246,6 +246,10 @@ jobs: vp run type-check:tsgo vp run build vp run test navigation-utils.test.ts real-browser-flicker.test.tsx workflow-parallel-limit.test.tsx + - name: viteplus-ws-repro + node-version: 24 + command: | + vp test run exclude: # frm-stack uses Docker (testcontainers) which doesn't work the same way on Windows - os: windows-latest diff --git a/ecosystem-ci/patch-project.ts b/ecosystem-ci/patch-project.ts index 7b3350c666..9215eae5dd 100644 --- a/ecosystem-ci/patch-project.ts +++ b/ecosystem-ci/patch-project.ts @@ -21,6 +21,18 @@ const cwd = directory ? join(repoRoot, directory) : repoRoot; // run vp migrate const cli = process.env.VITE_PLUS_CLI_BIN ?? 'vp'; +// Projects that already have vite-plus need it removed before migration so +// vp migrate treats them as fresh and applies tgz overrides. Without this, +// vp migrate detects "already using Vite+" and skips override injection. +const forceFreshMigration = 'forceFreshMigration' in repoConfig && repoConfig.forceFreshMigration; +if (forceFreshMigration) { + const pkgPath = join(cwd, 'package.json'); + const pkg = JSON.parse(await readFile(pkgPath, 'utf-8')); + delete pkg.devDependencies?.['vite-plus']; + delete pkg.dependencies?.['vite-plus']; + await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8'); +} + if (project === 'rollipop') { const oxfmtrc = await readFile(join(repoRoot, '.oxfmtrc.json'), 'utf-8'); await writeFile( diff --git a/ecosystem-ci/repo.json b/ecosystem-ci/repo.json index 7a64745f08..e1aa9fc242 100644 --- a/ecosystem-ci/repo.json +++ b/ecosystem-ci/repo.json @@ -54,5 +54,11 @@ "repository": "https://github.com/fengmk2/vite-vue-vercel.git", "branch": "main", "hash": "f2bf9fc40880c6a80f5d89bff70641c2eeaf77ef" + }, + "viteplus-ws-repro": { + "repository": "https://github.com/Charles5277/viteplus-ws-repro.git", + "branch": "main", + "hash": "451925ad7c07750a23de1d6ed454825d0eb14092", + "forceFreshMigration": true } } diff --git a/packages/test/build.ts b/packages/test/build.ts index 8def7e6465..4ed27b0039 100644 --- a/packages/test/build.ts +++ b/packages/test/build.ts @@ -302,9 +302,18 @@ async function mergePackageJson(pluginExports: Array<{ exportPath: string; shimF // browser-provider exports. Browser code uses index.js which is safe. // This separation prevents Node.js-only code (like __vite__injectQuery) from being // loaded in the browser, which would cause "Identifier already declared" errors. + // + // IMPORTANT: The 'browser' condition must come BEFORE 'node' because vitest passes + // custom --conditions (like 'browser') to worker processes when frameworks like Nuxt + // set edge/cloudflare presets. Without the 'browser' condition here, Node.js would + // match 'node' first, loading index-node.js which imports @vitest/browser/index.js, + // which imports 'ws'. With --conditions browser active, 'ws' resolves to its browser + // stub (ws/browser.js) that doesn't export WebSocketServer, causing a SyntaxError. + // See: https://github.com/voidzero-dev/vite-plus/issues/831 if (destPkg.exports['.'] && destPkg.exports['.'].import) { destPkg.exports['.'].import = { types: destPkg.exports['.'].import.types, + browser: destPkg.exports['.'].import.default, node: './dist/index-node.js', default: destPkg.exports['.'].import.default, }; diff --git a/packages/test/package.json b/packages/test/package.json index 5d2c8d0641..6a96280eef 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -37,6 +37,7 @@ ".": { "import": { "types": "./dist/index.d.ts", + "browser": "./dist/index.js", "node": "./dist/index-node.js", "default": "./dist/index.js" },