This article is published in English.
Vite 8 merged its bundlers into Rolldown—what broke
Vite 8 defaults to Rolldown for dev and production. Real CJS interop breaks, chunk migration pitfalls, and a safe checklist before you trust green CI.
For years Vite secretly ran two different bundlers — one while you developed, another when you shipped. Rolldown ends that split. The speed gains are real. The breakage list is real too.
Many teams know the symptom without naming the cause: local server is green, production is red, and the root is not a typo. The runtime that served modules in development and the toolchain that packaged them for production disagreed about an edge case. In Vite that disagreement was structural: esbuild transformed during development, Rollup built for production, and the glue was good enough that the seam stayed invisible — until it did not.
Vite 8 closes the seam with one Rust bundler: Rolldown. Benchmarks look strong. So does the catalog of apps that broke when years of dual-engine quirks suddenly had nowhere to hide. Knowing both sides is how you upgrade without a surprise incident.
What changed in Vite 8
The dual-engine bet was rational in 2020. A from-scratch production bundler is multi-year work. esbuild already transformed quickly; Rollup already owned the plugin ecosystem. Wiring them together was pragmatic. It also created lasting risk: two tools reading the same sources differently, especially around CommonJS interop — the awkward bridge between require() modules and modern ESM.
Rolldown is ownership of that whole problem in one engine. Rust implementation, Rollup-shaped plugin API (most plugins keep working), 1.0 stable on May 7, 2026 with a locked API meant for production bets. Vite 8 itself stabilized March 12, 2026 and made Rolldown the default with no opt-in. Transforms and minification that used to sit in esbuild now sit in Oxc, another Rust toolchain from VoidZero (the same org behind Rolldown).
Headline: production builds can land 10–30× faster than classic Rollup. Development mode is the quieter story. “Full bundle mode” packages the app in development the same way production does, instead of serving raw per-file ESM. Early numbers claim about 3× faster cold start, ~40% faster full reloads, and roughly 10× fewer network requests. Large codebases had already outgrown unbundled ESM in dev; this closes that gap.
The structural win is simpler: one engine for both modes. The old class of “dev interop ≠ prod interop” bugs becomes impossible because there is no second bundler left to disagree.
What actually broke
Migration was not free, and glossing that over helps nobody planning an upgrade.
Stricter CommonJS interop broke packages. Ambiguous CJS exports are handled differently than the old esbuild+Rollup pair. Without module.exports.__esModule and without a default property, Rolldown may bind an import to the entire module.exports object instead of guessing a default the way the permissive stack did:
// This used to just work under Vite 7 (esbuild + Rollup)
import DOMPurify from 'dompurify';
DOMPurify.sanitize(input);
// Under Rolldown's stricter CJS interop, this can throw:
// TypeError: e is not a function
// because the import resolved to the whole exports object,
// not the function you expected
Dangerous property of this class: CI usually misses it. jsdom or mocked suites rarely execute the real production artifact. Failures appear when a browser loads the built output. Vite’s legacy.inconsistentCjsInterop: true restores the old permissive behavior while you hunt the dependency.
manualChunks is deprecated for advancedChunks. The swap is not find-and-replace. Teams have seen ReferenceError: Cannot access 'x' before initialization from chunk-order side effects after regrouping, and at least one report described 575 chunks under default Rolldown chunking before manual tuning.
// Old, now-deprecated approach
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
}
// Rolldown's replacement - more powerful, but a real migration
build: {
rolldownOptions: {
output: {
advancedChunks: {
groups: [
{ name: 'vendor', test: /node_modules/, priority: 100 },
],
},
},
},
}
Documented case: Cloudflare’s @cloudflare/style-provider (hybrid ESM+CJS) hit createRenderer is not a function because Rolldown emitted an anonymous, unreachable initializer for the CJS half. The patch aliased the package to its CJS entry in Vite config — plain CJS through Rolldown’s interop was fine; the hybrid shape was not.
Outside app code: Rolldown’s native Rust binding failed to load inside StackBlitz WebContainers, knocking out many browser playground templates until projects pinned Vite 7 while upstream tracked the issue.
Safer migration checklist
Teams that finished the jump converge on specifics, not “upgrade and pray.”
Mysterious “Vite 7 worked, Vite 8 fails” bugs: try experimental: { enableNativePlugin: false } first. Native Rust plugins are default now; turning them off fixes a surprising share of opaque breakages.
Load the real production bundle in a real browser before deploy. jsdom will not catch the CJS interop class unless you execute the built artifact.
Treat manualChunks → advancedChunks as a real project with its own test pass. Chunk-order bugs look fine until a particular path runs.
De-risk with rolldown-vite (Vite 7 + Rolldown preview) against your codebase before committing to Vite 8.
If a critical dependency is not Rolldown-ready yet, staying on Vite 7 for that build is a valid choice — better than inventing fragile workarounds under deadline.
Who should expect pain
Standard ESM dependencies and light/default chunking: upgrades are usually smooth, and parity alone is worth it. Custom manualChunks, hybrid CJS/ESM packages, or unusual hosts (browser sandboxes, WebContainers): budget migration time and browser-test the artifact. Those failures pass green CI and only appear for real users on real bundles.
Bigger lesson
Whenever two systems that used to paper over each other’s edges get welded into one, previously invisible seams surface all at once. That does not mean unification was wrong. Dev/prod parity is a real structural upgrade and the speed numbers hold up. It means “we removed the disagreement” and “a wave of specific, findable bugs will appear during the transition” are the same fact on different calendar days. Skepticism about Rolldown is the wrong posture; skepticism about green CI without a browser-loaded production bundle is the right one.
What to put on the migration ticket
Write the upgrade as an engineering change with acceptance criteria, not as a dependency bump.
Suggested criteria:
- Production build completes under Rolldown with the same public assets you expect.
- Critical user journeys run against the built bundle in a real browser (not only unit tests).
- Known hybrid CJS dependencies are either aliased, upgraded, or covered by
legacy.inconsistentCjsInteropwith an owner and expiry date. - Chunk strategy is explicitly reviewed: either accept Rolldown defaults after measuring request count, or migrate
manualChunkstoadvancedChunkswith a dedicated test pass. - Environments that cannot load native bindings (for example some WebContainer hosts) have a documented pin or workaround.
If any criterion fails, stay on Vite 7 or on rolldown-vite until it passes. Shipping a faster bundler that breaks production is not a performance win.
Why parity bugs feel personal
Developers trust the local server. When the local server and the production build stop arguing with each other, bugs that used to hide in the argument appear in one place. That can feel like Rolldown “introduced” failures that were always latent in CJS ambiguity or chunk graphs. Naming that pattern reduces panic: you are not chasing random regressions; you are surfacing seams the dual-engine era papered over.
Keep the speed numbers. Keep the single-engine design. Just do not confuse a green unit suite with proof that the built artifact works.