1.2 · difficulty 2/4 · 10 min read
Vite 8's Unified Architecture
How does Rolldown unify the dev and build phases? What is the architectural evolution compared to the dual-engine era of Vite 5/6/7?
Architectural evolution timeline
To understand Vite 8's architecture, start with the timeline:
Vite 2–6 (2021–2025)
Dev: esbuild (Go) → single-file transform, blazing fast
Build: Rollup (JS) → full bundle, tree-shaking
Issue: two phases use different engines, behavior is inconsistent
Vite 7 (2025-06)
Dev: esbuild (Go) → same as above
Build: Rollup (JS) → same as above
Added: rolldown-vite experiment → early access to Rolldown
Issue: dual-engine still exists
Vite 8 (2026-03, stable)
Dev: Rolldown (Rust) → transform
Build: Rolldown (Rust) → full bundle
Result: single unified engine! dev/build behavior is consistentWhy the two phases needed to be unified
In Vite 7 and earlier, developers frequently ran into situations like this:
pnpm dev # ✅ everything works
pnpm build # ❌ some import path resolution failsOr the reverse:
pnpm build # ✅ output is correct
pnpm dev # ❌ some plugin hook never firesThe root cause of these bugs was the dual-engine setup:
- esbuild's resolve logic ≠ Rollup's
resolveIdhook - Rollup's
generateBundledoes not fire during dev (dev goes through esbuild) - The two transform pipelines each have their own source map generation rules
After Vite 8 unified both phases with Rolldown, the same plugin system and the same transform pipeline run in both dev and build. This eliminates the inconsistency at the root.
Vite 8's internal architecture diagram
Vite 8 Dev Server
┌─────────────────────────────────┐
│ │
Browser request │ ┌───────────────────────┐ │
GET /src/App.tsx ──┼──▶│ Rolldown Transform │ │
│ │ Pipeline │ │
│ │ ① resolveId hooks │ │
│ │ ② load hooks │ │
│ │ ③ transform hooks │ │
│ │ ④ OXC TS/JSX compile │ │
│ └────────────┬──────────┘ │
│ │ │
│ return ESM │
└─────────────────────────────────┘
│
▼
Browser renders
Vite 8 Build (pnpm build)
┌─────────────────────────────────┐
│ │
│ ┌───────────────────────┐ │
All source files ───┼──▶│ Rolldown Bundle │ │
│ │ Pipeline │ │
│ │ ① module graph analysis │
│ │ ② tree-shaking │ │
│ │ ③ code splitting │ │
│ │ ④ OXC minify │ │
│ └────────────┬──────────┘ │
│ │ │
│ dist/ output │
└─────────────────────────────────┘Both phases share the same Plugin Hook system. Write a plugin once — it works in both dev and build.
New defaults in Vite 8
Compared to Vite 7, Vite 8 changes several defaults:
| Config | Vite 7 default | Vite 8 default |
|---|---|---|
| Bundler | esbuild + Rollup | Rolldown |
| CSS Minifier | esbuild | lightningcss |
| Default target | baseline-widely-available | baseline-widely-available (unchanged) |
@vitejs/plugin-react | v5 (Babel) | v6 (OXC Refresh) |
| Devtools | none | built-in devtools option |
lightningcss replaces esbuild CSS minification
The CSS processing pipeline in Vite 8:
.css file
↓
PostCSS (if configured)
↓
lightningcss (minify + prefix) ← added as a regular dependency in Vite 8
↓
output CSSlightningcss is implemented in Rust and provides more complete CSS minification than esbuild (supports more modern CSS syntax).
@vitejs/plugin-react v6
The vite.config.ts for a React project looks essentially the same:
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
export default defineConfig({
plugins: [react()], // same syntax
})But v6 internally:
- React Fast Refresh is powered by OXC (v5 used Babel)
- Babel is no longer a dependency, cold start is faster
- React Compiler requires separate configuration (not auto-integrated)
Developer perspective: what changes in Vite 8
What you won't notice (transparent upgrade)
vite.config.tssyntax is identical- Plugin API is backward-compatible with Rollup
pnpm dev/pnpm buildcommands are unchangedimport.meta.env/import.meta.hotare unchanged
What you will notice
- Faster cold start: Rolldown's dependency pre-bundling is faster than esbuild's
- More consistent dev/build: no more mysterious "works in dev but breaks in build" bugs
- Smaller CSS output: lightningcss achieves a higher compression ratio
- More complete plugin hooks: hooks that previously only fired during build now also fire during dev
Self-check
- What are the two specific engines in Vite 7's "dual-engine" setup? Which phase does each handle?
- Why do some plugin hooks not fire during the dev phase in Vite 7? How does Vite 8 solve this?
- After upgrading to Vite 8, do you need to change anything in
vite.config.ts? - What is the core difference between
@vitejs/plugin-reactv6 and v5?
// What is wrong with this plugin in Vite 7 dev mode?
// Does the problem still exist after upgrading to Vite 8?
function analyzeBundlePlugin(): Plugin {
const stats: { name: string; size: number }[] = []
return {
name: "vite-plugin-analyze",
generateBundle(_, bundle) {
for (const [name, chunk] of Object.entries(bundle)) {
if (chunk.type === "chunk") {
stats.push({ name, size: chunk.code.length })
}
}
console.table(stats)
},
}
}
// Question 1: during vite dev, will console.table be called?
// Question 2: during vite build?
// Question 3: do both answers change under Vite 8?