Vite 8 Skill
Configure, migrate, and debug Vite 8 projects with the repo's preferred Vite-native patterns.
Before You Start
This skill focuses on the Vite 8 architecture shift, not generic bundler advice.
| Metric | Without Skill | With Skill |
|---|
| Migration Time | ~120 min | ~40 min |
| Common Config Errors | 6+ | 0 |
| Token Usage | High (trial/error) | Low (known patterns) |
Known Issues This Skill Prevents
- Broken builds from leaving in Vite 8 configs where is needed
- Outdated JS/TS transform setup from using instead of
- Plugin code checking stale booleans instead of environment-aware APIs
- HMR bugs from using deprecated patterns instead of
- SSR/runtime confusion from older mental models instead of Module Runner
- Performance regressions from missing hook filters in Rust↔JS plugin boundaries
- Slow startup and request waterfalls from barrel files, missing warmup, or loose import resolution
Quick Start
Step 1: Start with a typed Vite 8 config
typescript
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
server: {
port: 5173,
},
build: {
target: 'baseline-widely-available',
rolldownOptions: {
output: {
manualChunks: undefined,
},
},
},
});
Why this matters: Vite 8 is built around Rolldown/Oxc-era config and defaults. Starting from
with Vite 8 options avoids backporting old Rollup/esbuild assumptions into a new architecture.
Step 2: Prefer Vite 8 terminology in plugins and SSR code
typescript
import type { Plugin } from 'vite';
export function inspectEnvironment(): Plugin {
return {
name: 'inspect-environment',
configEnvironment(name) {
if (name === 'ssr') {
return {
resolve: {
conditions: ['node'],
},
};
}
},
};
}
Why this matters: Vite 8 leans on named environments and environment-aware plugin behavior. That is a better fit than older client-vs-SSR shortcuts.
Step 3: Use the correct one-shot commands
bash
vite dev
vite build
vite build --ssr src/entry-server.ts
vite preview
Why this matters: These are the stable command surfaces agents and CI flows should target. Avoid inventing framework-specific abstractions unless the project already uses them.
Critical Rules
Always Do
- Use with for repo-facing Vite 8 work
- Prefer over legacy
- Prefer over for new Vite 8 transform configuration
- Use named environments when plugin or SSR behavior differs by runtime
- Use hook filters when writing performance-sensitive or plugins
- Reach for Module Runner concepts when debugging modern SSR/runtime execution
- Use explicit file extensions and review barrel files when performance work matters
- Keep Vite plugin code ESM-first
Never Do
- Never introduce new / examples as the preferred Vite 8 path
- Never treat as the forward-looking HMR hook in Vite 8
- Never assume a single client/SSR split is enough for all runtimes
- Never suggest CommonJS config as the default for new Vite work
- Never skip review when SSR dependencies misbehave
Common Mistakes
Wrong - legacy build config:
typescript
export default defineConfig({
build: {
rollupOptions: {
external: ['react'],
},
},
esbuild: {
jsxInject: "import React from 'react'",
},
});
Correct - Vite 8 config:
typescript
export default defineConfig({
build: {
rolldownOptions: {
external: ['react'],
},
},
oxc: {
jsxInject: "import React from 'react'",
},
});
Why: Vite 8 moved its preferred build and transform configuration surface to Rolldown and Oxc.
Wrong - stale HMR hook:
typescript
export default function plugin() {
return {
name: 'old-hmr',
handleHotUpdate(ctx) {
return ctx.modules;
},
};
}
Correct - environment-aware HMR:
typescript
export default function plugin() {
return {
name: 'env-hmr',
hotUpdate(ctx) {
return ctx.modules;
},
};
}
Why: is the environment-aware Vite 8 direction, while
is legacy-oriented.
Known Issues Prevention
| Issue | Root Cause | Solution |
|---|
| Config migration stalls | Old Rollup/esbuild settings copied forward | Migrate to and |
| Plugin logic breaks in non-standard runtimes | Plugin assumes only client/SSR | Use named and |
| HMR customization feels brittle | Legacy HMR hook carried forward | Prefer and environment-aware flows |
| SSR dependency crashes | Externalization assumptions are wrong | Review and runtime-specific needs |
| Dev/build behavior diverges | Config ignores Vite 8's unified engine model | Validate both and under Rolldown |
| Plugin performance drops | Too much JS-side hook work | Add hook filters and narrower matching |
| Cold starts are sluggish | Heavy hot paths are not warmed and import graph is noisy | Review , explicit extensions, and barrel-file usage |
Bundled Resources
References
- Core config and CLI patterns →
references/core-config-reference.md
- Environment-aware plugin authoring →
references/plugin-environment-reference.md
- Build, SSR, and migration guidance →
references/build-ssr-migration-reference.md
- Performance and dev-server heuristics →
references/performance-devserver-reference.md
- Reference index →
Configuration Reference
vite.config.ts
typescript
import { defineConfig } from 'vite';
export default defineConfig({
build: {
target: 'baseline-widely-available',
rolldownOptions: {
output: {
chunkFileNames: 'assets/[name]-[hash].js',
},
},
},
oxc: {
jsxInject: "import React from 'react'",
},
environments: {
ssr: {
resolve: {
conditions: ['node'],
},
},
},
css: {
lightningcss: {},
},
});
Key settings:
- : Preferred Vite 8 build customization surface
- : Preferred JS/TS transform configuration surface in new Vite 8 examples
- : Use when runtime behavior differs across client/SSR/edge-like targets
- : Reflects Vite 8's modern CSS processing direction
- : Useful in large apps where cold-start waterfalls hit the same hot files repeatedly
Project Structure
my-app/
├── src/
├── index.html
├── vite.config.ts
├── package.json
└── tsconfig.json
Why this matters: Vite 8 still rewards simple, explicit project layout. Complexity should come from runtime environments and plugin boundaries, not from hiding the core config.
Performance heuristic: If startup feels bad, inspect import-graph shape before chasing exotic bundler flags. Barrel files, omitted extensions, and lack of warmup often matter more than another layer of config cleverness.
Common Patterns
Environment-aware plugin pattern
typescript
import type { Plugin } from 'vite';
export function envAwarePlugin(): Plugin {
return {
name: 'env-aware-plugin',
transform: {
filter: {
id: /\.(ts|tsx)$/,
},
handler(code, id) {
return {
code,
map: null,
};
},
},
configEnvironment(name) {
if (name === 'ssr') {
return {
resolve: {
conditions: ['node'],
},
};
}
},
};
}
SSR build pattern
bash
vite build
vite build --ssr src/entry-server.ts
vite preview
Module Runner mental model
typescript
// Pseudocode sketch
const mod = await moduleRunner.import('/src/entry-server.ts');
Use this model when modern Vite SSR debugging is really about runtime execution boundaries rather than plain bundling.
Dependencies
Required
| Package | Version | Purpose |
|---|
| ^8 | Build tool, dev server, plugin host |
| >=20.19 or >=22.12 | Required Vite 8 runtime |
Optional
| Package | Version | Purpose |
|---|
| latest | Typed and plugin authoring |
| framework plugin packages | latest | React/Vue/Svelte/etc integrations |
Official Documentation
Troubleshooting
Old config keys no longer feel right
Symptoms: A config works but reads like pre-Vite-8 code, or new options are not behaving as expected.
Solution:
typescript
build: {
rolldownOptions: {},
}
oxc: {}
SSR runtime behavior is unclear
Symptoms: The bundle builds, but runtime execution differs by environment or platform.
Solution:
Review
,
, Module Runner expectations, and
before changing unrelated bundler settings.
Plugin hook work feels slow or noisy
Symptoms: Custom plugins add overhead in dev or build.
Solution:
Use hook filters and narrow matching patterns so only relevant files cross the Rust↔JS boundary.
Setup Checklist
Before using this skill, verify: