fix(bundler): disable SSRStaticReplace in vite dev mode#739
Conversation
In vite dev mode (serve), both SSR and client environments share the same vite dev server. The SSRStaticReplace plugin was replacing `head.ssr` with `false` for all environments, causing useHead to always use clientUseHead instead of head.push during SSR renders. This broke reactive ref resolution in SSR because clientUseHead uses Vue watchers (client behavior) instead of synchronous push (SSR behavior). The fix disables the static replacement in dev mode, preserving the runtime `head.ssr` value so each environment behaves correctly.
📝 WalkthroughWalkthroughModified the SSRStaticReplace Vite plugin to add an Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Bundle Size Analysis
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/bundler/src/unplugin/SSRStaticReplace.ts (1)
47-58: Makeapply()state assignment idempotent.At Line 52 and Line 56,
enabled/ssrare only flipped in one direction. Ifapply()is invoked again on the same plugin instance with a different env, stale state can leak. Set both flags fromenvevery call.♻️ Proposed refactor
apply(_config: UserConfig, env: ConfigEnv): boolean { - // In dev mode (serve), both SSR and client environments share the same - // vite dev server. Statically replacing head.ssr would force one value - // for both environments, breaking SSR renders. Only apply during builds - // where SSR and client are separate passes. - if (env.command === 'serve') { - enabled = false - return true - } - if (env.isSsrBuild) - ssr = true + // Keep plugin state derived from current env on every apply call. + enabled = env.command !== 'serve' + ssr = !!env.isSsrBuild return true },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bundler/src/unplugin/SSRStaticReplace.ts` around lines 47 - 58, The apply() method mutates plugin-level flags enabled and ssr only in one direction causing stale state when apply() is called multiple times; make assignments idempotent by explicitly setting enabled = (env.command !== 'serve') and ssr = !!env.isSsrBuild inside apply() so both flags reflect the current env on every invocation (update the apply function where enabled and ssr are currently toggled).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/bundler/src/unplugin/SSRStaticReplace.ts`:
- Around line 47-58: The apply() method mutates plugin-level flags enabled and
ssr only in one direction causing stale state when apply() is called multiple
times; make assignments idempotent by explicitly setting enabled = (env.command
!== 'serve') and ssr = !!env.isSsrBuild inside apply() so both flags reflect the
current env on every invocation (update the apply function where enabled and ssr
are currently toggled).
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ee4914de-eaeb-4a40-8f6e-e1263be42078
📒 Files selected for processing (2)
packages/bundler/src/unplugin/SSRStaticReplace.tspackages/bundler/test/ssrStaticReplace.test.ts
❓ Type of change
📚 Description
In vite dev mode, SSR and client environments share the same dev server, but
SSRStaticReplacewas rewritinghead.ssrtofalsefor both, forcinguseHeaddown theclientUseHeadpath during SSR renders. That broke reactive ref resolution in SSR becauseclientUseHeadrelies on Vue watchers rather than synchronoushead.push.Fix disables the static replacement in dev mode so the runtime
head.ssrvalue is preserved and each environment behaves correctly. Unit tests cover client builds, SSR builds, and dev mode.