Describe the bug
A client-only build can fail because Vite's import analysis resolves dynamic imports that are intended to be dead/server-only.
Guards like:
export const preload = async => {
if (false /*or import.meta.env.SSR*/) {
// dead code now //
/* server code */
const { join } = await import('node:path')
}
}
— correctly remain dead and are not analyzed by the client build, but patterns that create "syntactically present" dynamic imports after unreachable statements like:
export const preload = async => {
return;
return void 0;
if (true) return;
throw new Error();
// dead code now //
/* server code */
const { join } = await import('node:path')
}
— are still picked up by the import analyzer and cause the client build to try to resolve server-only modules, resulting in build errors.
vite v7.3.0 building client environment for production...
[plugin vite:resolve] Module "node:path" has been externalized for browser compatibility, imported by "/home/projects/vitejs-vite-a4nfutc9/src/main.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
✓ 10 modules transformed.
✗ Build failed in 357ms
error during build:
src/main.js (1:9): "join" is not exported by "__vite-browser-external", imported by "src/main.js".
Expected behavior
Dynamic imports that are unreachable or inside explicit server-only guards (e.g. if (false) { ... } or if (import.meta.env.SSR) { ... }) should not be considered by client-side import analysis and should not be resolved/included by the client build.
Actual behavior
Vite's import analysis still detects and resolves some dynamic imports when they appear syntactically (even if preceded by return;, throw, or other constructs that make them unreachable), causing client builds to fail or incorrectly include server-only modules.
Reproduction
https://stackblitz.com/edit/vitejs-vite-a4nfutc9?file=src%2Fmain.js
Steps to reproduce
Run pnpm install then run pnpm build. In main.js, uncomment preload2 code and run build to see the error.
System Info
System:
OS: Windows 10 10.0.19045
Memory: 36.45 GB / 61.83 GB
Binaries:
Node: 22.14.0 - C:\Program Files\nodejs\node.EXE
npm: 10.9.2
pnpm: 9.15.9
Browsers:
Chrome: 143.0.7499.110
Edge: Chromium (140.0.3485.54)
npmPackages:
vite: ^7.3.0 => 7.3.0
Used Package Manager
pnpm
Logs
Click to expand!
❯ pnpm build
> vite-starter@0.0.0 build /home/projects/vitejs-vite-a4nfutc9
> vite build
vite v7.3.0 building client environment for production...
✓ 7 modules transformed.
dist/index.html 0.45 kB │ gzip: 0.29 kB
dist/assets/index-XlyKSLnJ.css 1.20 kB │ gzip: 0.62 kB
dist/assets/index-CgYMNPpC.js 2.58 kB │ gzip: 1.37 kB
✓ built in 449ms
~/projects/vitejs-vite-a4nfutc9 2s
❯ pnpm build
> vite-starter@0.0.0 build /home/projects/vitejs-vite-a4nfutc9
> vite build
vite v7.3.0 building client environment for production...
[plugin vite:resolve] Module "node:path" has been externalized for browser compatibility, imported by "/home/projects/vitejs-vite-a4nfutc9/src/server-only.js". See https://vite.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
✓ 10 modules transformed.
✗ Build failed in 357ms
error during build:
src/server-only.js (1:9): "join" is not exported by "__vite-browser-external", imported by "src/server-only.js".
file: /home/projects/vitejs-vite-a4nfutc9/src/server-only.js:1:9
1: import { join } from 'node:path';
^
2:
3: join('/a', 'b');
at getRollupError (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/parseAst.js:568:41)
at Module.error (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/parseAst.js:564:42)
at Module.error (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:17047:29)
at Module.traceVariable (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:17503:29)
at ModuleScope.findVariable (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:15166:39)
at Identifier.bind (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:5487:40)
at CallExpression.bind (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:2854:23)
at CallExpression.bind (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:12197:15)
at ExpressionStatement.bind (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:2854:23)
at Program.bind (file:///home/projects/vitejs-vite-a4nfutc9/node_modules/rollup/dist/es/shared/node-entry.js:2850:28)
ELIFECYCLE Command failed with exit code 1.
Validations
Describe the bug
A client-only build can fail because Vite's import analysis resolves dynamic imports that are intended to be dead/server-only.
Guards like:
— correctly remain dead and are not analyzed by the client build, but patterns that create "syntactically present" dynamic imports after unreachable statements like:
— are still picked up by the import analyzer and cause the client build to try to resolve server-only modules, resulting in build errors.
Expected behavior
Dynamic imports that are unreachable or inside explicit server-only guards (e.g.
if (false) { ... }orif (import.meta.env.SSR) { ... }) should not be considered by client-side import analysis and should not be resolved/included by the client build.Actual behavior
Vite's import analysis still detects and resolves some dynamic imports when they appear syntactically (even if preceded by
return;,throw, or other constructs that make them unreachable), causing client builds to fail or incorrectly include server-only modules.Reproduction
https://stackblitz.com/edit/vitejs-vite-a4nfutc9?file=src%2Fmain.js
Steps to reproduce
Run
pnpm installthen runpnpm build. Inmain.js, uncommentpreload2code and run build to see the error.System Info
System: OS: Windows 10 10.0.19045 Memory: 36.45 GB / 61.83 GB Binaries: Node: 22.14.0 - C:\Program Files\nodejs\node.EXE npm: 10.9.2 pnpm: 9.15.9 Browsers: Chrome: 143.0.7499.110 Edge: Chromium (140.0.3485.54) npmPackages: vite: ^7.3.0 => 7.3.0Used Package Manager
pnpm
Logs
Click to expand!
Validations