Skip to content

fix(optimizer): stabilize server dep outputs during discovery#21818

Open
agcty wants to merge 4 commits intovitejs:mainfrom
agcty:codex/fix-ssr-optimizer-stability
Open

fix(optimizer): stabilize server dep outputs during discovery#21818
agcty wants to merge 4 commits intovitejs:mainfrom
agcty:codex/fix-ssr-optimizer-stability

Conversation

@agcty
Copy link
Copy Markdown

@agcty agcty commented Mar 11, 2026

Closes #19323

Summary

When a non-browser dev environment discovers new optimized dependencies during request handling, the dep optimizer can reshuffle shared chunks and rewrite previously optimized server entry outputs.

That causes Vite to treat the rerun as incompatible and trigger the full-reload path, which is acceptable for browsers but unsafe for in-flight SSR/RSC requests.

This change makes server-side dep optimization runs with runtime discovery enabled preserve module boundaries by default. That keeps previously optimized server entry outputs stable when new deps are added, so the optimizer can commit the rerun without forcing a reload.

Scope

This only applies when:

  • the environment consumer is server
  • optimizeDeps.noDiscovery === false

Client dep optimization is unchanged, and explicit server no-discovery prebundles are unchanged.

Implementation

  • default server discovery runs to Rolldown output.preserveModules = true
  • default output.preserveModulesRoot to environment.config.root
  • keep any user-provided preserveModules / preserveModulesRoot overrides intact

Why this approach

The bug is caused by unstable optimizer output for long-lived server environments, not by missing late runtime error handling.

Stabilizing the optimizer output graph is a smaller and more architectural fix than trying to recover after modules have already executed with stale chunk references.

Tradeoff

This gives up some bundling compactness for server dep optimization in exchange for stable outputs:

  • more files under deps_ssr / deps_rsc
  • potentially a bit more cold-path filesystem work
  • less aggressive shared chunking for server dep optimizer output

That tradeoff is intentionally limited to server environments with runtime discovery, where correctness matters more than minimizing the number of optimized cache files.

Tests

Added a regression test that builds a synthetic dep graph where:

  • two optimized server deps initially share a generated chunk
  • adding a third dep causes the default chunking strategy to rewrite those existing entry outputs
  • the server-optimized outputs now remain byte-stable across that rerun

Validated with:

  • pnpm exec vitest run packages/vite/src/node/__tests__/optimizer.spec.ts
  • pnpm exec vitest run packages/vite/src/node/__tests__/scan.spec.ts
  • pnpm exec vitest run packages/vite/src/node/ssr/__tests__/ssrLoadModule.spec.ts
  • pnpm exec vitest run packages/vite/src/node/__tests__/environment.spec.ts

I also verified the Cloudflare/RSC repro locally against this Vite build. Late @conform-to/* discovery still occurs, but the rerun now logs optimized dependencies unchanged instead of optimized dependencies changed. reloading.

@agcty agcty marked this pull request as ready for review March 12, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dependencies optimization in ssr Environments during dev request handling can cause inconsistent states

1 participant