Vite 32 ⚡ Cheatsheet
This cheatsheet covers Vite 8 (Rolldown-powered) with the Environment API, advanced chunking, Oxc transforms, and the experimental Bundled Dev Mode. It is scoped to the decisions you make mid-build, not to every option in the config.
The Core Shift in Vite 8
Vite 8 replaced esbuild + Rollup with Rolldown (Rust bundler) and Oxc (Rust transformer/minifier) . The build is 7.7× faster, memory usage is halved, and the dev server starts roughly 3× faster .
| Metric | Vite 7 | Vite 8 |
|---|---|---|
| Build time (Linear) | 46s | 6s |
| Dev server startup | ~3s | ~1s |
| Memory usage | ~800MB | ~400MB |
The Config Renames
Every old option still works through an auto-conversion shim, but the shim will be removed. The new names are the ones to write.
| Vite 7 | Vite 8 |
|---|---|
build.rollupOptions | build.rolldownOptions |
worker.rollupOptions | worker.rolldownOptions |
optimizeDeps.esbuildOptions | optimizeDeps.rolldownOptions |
esbuild | oxc |
esbuild.jsxFactory | oxc.jsx.pragma |
esbuild.jsxFragment | oxc.jsx.pragmaFrag |
esbuild.jsx: 'automatic' | oxc.jsx: { runtime: 'automatic' } |
transformWithEsbuild | transformWithOxc |
The esbuild.banner and esbuild.footer options have no Oxc equivalent. Use a custom plugin transform hook instead .
The Minifier and the Casing Trap
JavaScript minification now uses Oxc by default. CSS minification uses Lightning CSS . The build.minify: 'esbuild' fallback requires esbuild as a dev dependency and is deprecated.
The Oxc minifier options live on build.rolldownOptions.output.minify, and the casing is snake_case. drop_console works; dropConsole silently does nothing .
// ✅ Correct
build: {
rolldownOptions: {
output: {
minify: {
compress: {
drop_console: true, // snake_case
},
},
},
},
},
Property mangling (mangleProps, reserveProps, mangleQuoted, mangleCache) is not supported by Oxc .
The Chunking Shift: advancedChunks
manualChunks is deprecated. The Vite 8 mechanism is advancedChunks, a declarative grouping system with priority and size constraints .
build: {
rolldownOptions: {
output: {
advancedChunks: {
groups: [
{
name: 'react-vendor',
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
priority: 20,
},
{
name: 'charts',
test: /[\\/]node_modules[\\/](recharts|d3)[\\/]/,
priority: 15,
maxSize: 300000,
},
{
name: 'vendor',
test: /[\\/]node_modules[\\/]/,
priority: 10,
maxSize: 500000,
},
],
},
},
},
},
priority decides which group wins when a module matches multiple tests. maxSize auto-splits a group that grows too large . The manualChunks object form is removed; the function form is deprecated.
The Environment API (Stable from Vite 7)
The environments config declares multiple runtimes in a single build. The client and ssr environments are the baseline; edge is the third case that forces the abstraction .
export default defineConfig({
environments: {
client: { build: { outDir: 'dist/client' } },
ssr: { build: { outDir: 'dist/server', ssr: true } },
edge: {
resolve: { noExternal: true, conditions: ['edge', 'worker'] },
build: { outDir: 'dist/edge', target: 'es2022' },
},
},
});
Each environment has its own moduleGraph and transformRequest(). Plugins access the current environment with this.environment.name . The server.moduleGraph and ssrLoadModule APIs still work for backward compatibility, but the environment instances are the forward-compatible surface .
The Plugin Hook Filter
In Vite 8, transform hooks accept a filter property that moves the match check to Rust. The handler is only called when the filter matches, which avoids a Rust-to-JS call for non-matching modules .
transform: {
filter: {
id: /\.(ts|tsx)$/,
},
handler(code, id) {
return { code, map: null };
},
},
The id filter accepts a RegExp or a glob string. The moduleType and code filters are also available. The filter is only on resolveId, load, transform, and renderChunk .
The Library Mode Contract
Library mode has three manual steps that Vite does not do for you .
| Step | Configuration | Consequence if missed |
|---|---|---|
| Externalize peers | rolldownOptions.external | Duplicate runtime in consumer |
| Generate types | vite-plugin-dts | TypeScript sees no types |
| Map exports | exports field in package.json | Resolver fails |
export default defineConfig({
plugins: [dts({ include: ['src'], rollupTypes: true })],
build: {
lib: {
entry: resolve(__dirname, 'src/index.ts'),
name: 'MyLib',
fileName: (format) => `my-lib.${format}.js`,
},
rolldownOptions: {
external: ['react', 'react-dom', 'react/jsx-runtime'],
output: { globals: { react: 'React', 'react-dom': 'ReactDOM' } },
},
},
});
The package.json must declare peerDependencies for the externalized packages, and the exports map must point to the actual output filenames with types first .
The Bundled Dev Mode (Experimental)
For large applications, the unbundled dev server’s request count becomes the bottleneck. Bundled Dev Mode serves a Rolldown-bundled output during development .
| Metric | Unbundled | Bundled Dev Mode |
|---|---|---|
| 10,000 components startup | Baseline | ~15× faster |
| 10,000 components full reload | Baseline | ~10× faster |
| Linear cold start | Baseline | ~3× faster |
| Linear network requests | Baseline | ~10× fewer |
| HMR speed | ~50ms | Unchanged |
Enable with experimental.bundledDev: true or --experimental-bundle. The compatibility surface is narrower: third-party plugins and minor features may not work .
The CommonJS Interop Change
The default import from a CJS module now resolves to module.exports if the importer is .mjs, the nearest package.json has "type": "module", or module.exports.__esModule is not true. Otherwise it resolves to module.exports.default .
// Temporary escape hatch
legacy: { inconsistentCjsInterop: true }
The legacy option is deprecated. The permanent fix is to report the package or switch to an ESM version .
The SSR Primitives
Vite’s SSR support is low-level: middleware mode, transformIndexHtml, ssrLoadModule, and import.meta.env.SSR.
// The middleware server
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'custom',
});
app.use(vite.middlewares);
app.use('*all', async (req, res) => {
let template = fs.readFileSync('index.html', 'utf-8');
template = await vite.transformIndexHtml(url, template);
const { render } = await vite.ssrLoadModule('/src/entry-server.js');
const html = template.replace('<!--ssr-outlet-->', await render(url));
res.status(200).set({ 'Content-Type': 'text/html' }).end(html);
});
The ssrLoadModule loads the server entry without a bundle. The ssrFixStacktrace remaps the errors .
The Path Alias Dual Config
Vite does not read tsconfig.json paths. The alias must be declared in both files.
// tsconfig.json
"paths": { "@/*": ["./src/*"] }
// vite.config.ts
resolve: {
alias: { '@': path.resolve(__dirname, './src') },
},
Dynamic imports may require optimizeDeps.exclude: ['@'] to prevent the scanner from treating @ as an npm scope.
The Monorepo Linked Package Rule
Vite treats linked workspace packages as source, not as dependencies.
| Package type | Configuration |
|---|---|
| CommonJS | optimizeDeps.include: ['pkg'] + build.commonjsOptions.include |
| ESM | optimizeDeps.exclude: ['pkg'] |
| React duplicate | resolve.dedupe: ['react', 'react-dom'] + peer dep |
The resolve.preserveSymlinks option is a yarn workaround that breaks hoisted dependencies in some setups. Use it only when the linked package is not resolved otherwise.
The Deployment Routing Rule
A Vite SPA needs a history-fallback rewrite on the host. The rule is host-specific.
| Host | Rule |
|---|---|
| Netlify | /* /index.html 200 in _redirects |
| Vercel | "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] |
| Cloudflare Pages | /* /index.html 200 in _redirects |
| Nginx | try_files $uri $uri/ /index.html; |
The base option must match the deployment path. The router’s basename must match the base.
The CLI Quick Reference
vite # Dev server
vite build # Production build
vite preview # Preview the build
vite build --ssr # SSR build
vite --experimental-bundle # Bundled Dev Mode
vite --config my-config.js # Custom config
The One-Line Summary
Rolldown bundles. Oxc transforms. Environments separate. Chunks are declarative. Auth the actions, narrow the props, and place the boundary at the leaf.
The old config still works through the shims, but the new names are the ones that will survive. The advancedChunks is the chunking mechanism. The environments object is the multi-runtime mechanism. The filter is the plugin performance mechanism. The external is the library contract. The rest is the deployment.
Summary
| Area | Key change in Vite 8 |
|---|---|
| Bundler | Rolldown replaces Rollup and esbuild |
| Transformer | Oxc replaces esbuild |
| Config rename | rollupOptions → rolldownOptions, esbuild → oxc |
| Minifier | Oxc for JS, Lightning CSS for CSS |
| Chunking | advancedChunks replaces manualChunks |
| Environments | environments config for client/ssr/edge |
| Plugin filter | transform.filter moves the match to Rust |
| Library mode | Externalize peers, generate types, map exports |
| Bundled dev | experimental.bundledDev: true |
| CJS interop | Changed default import behavior |
Remember: Vite 8 is the Rolldown release. The build is faster, the config is renamed, and the chunking is declarative. The old options still work through the shims, but the shims are temporary. The advancedChunks is the chunking mechanism, the environments object is the multi-runtime mechanism, and the filter is the plugin performance mechanism. The rest is the deployment rule and the library contract. The cheatsheet is the decisions, and the decisions are the discipline.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!