Vite — Rules and Conventions
1. Philosophy
- Unbundled dev — Native ESM in browser during development. No bundle step = instant server start.
- ESM-first — Code authored as ES modules. CommonJS only for legacy deps.
- Plugin-driven — Core is minimal. Features via Rollup-compatible plugins.
- Build = Rollup — Production build uses Rollup under the hood. Config unified.
- TypeScript native —
tscfor type-checking (separate). Vite only transpiles.
2. Minimum Versions
| Technology | Minimum Version |
|---|---|
| Vite | 5.4+ |
| Node.js | 22+ |
| pnpm | 11+ |
3. Project Setup
Initialize
# New project
pnpm create vite@latest my-app -- --template react-ts
# Existing project: add Vite
pnpm add -D vite @vitejs/plugin-react
package.json scripts
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
}
}
4. Configuration — vite.config.ts
Essential structure
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
root: ".",
base: "/",
plugins: [react()],
server: {
port: 3000,
proxy: {
"/api": { target: "http://localhost:4000", changeOrigin: true },
},
},
build: {
outDir: "dist",
sourcemap: true,
minify: "esbuild",
cssCodeSplit: true,
assetsInlineLimit: 4096,
rollupOptions: {
output: {
manualChunks: { vendor: ["react", "react-dom"] },
},
},
},
resolve: {
alias: { "@": "/src" },
},
define: { __APP_VERSION__: JSON.stringify(process.env.npm_package_version) },
optimizeDeps: { include: ["react", "react-dom"] },
});
Key config rules
| Option | Rule | Why |
|---|---|---|
root |
Explicit, not implicit | Avoids cwd confusion in monorepos |
base |
Set for non-root deploy | GitHub Pages, subpath hosting |
plugins |
Official first, minimal | Reduces maintenance surface |
server.proxy |
For API dev only | Avoids CORS in dev |
build.minify |
'esbuild' (default) |
Fastest; 'terser' only if needed |
build.cssCodeSplit |
true (default) |
Enables parallel CSS loading |
build.assetsInlineLimit |
4096 (4kb) |
Inlines small assets as base64 |
resolve.alias |
@ → /src only |
One canonical alias |
define |
Only build-time constants | Replaces process.env in client code |
optimizeDeps.include |
Heavy deps only | Pre-bundles for faster dev start |
5. Plugins
Core philosophy
- Official plugins first:
@vitejs/plugin-react,@vitejs/plugin-vue, etc. - Minimal set: Each plugin adds dev/build overhead. Audit quarterly.
- Order matters: React plugin before other transform plugins.
Common patterns
// vite.config.ts
import react from "@vitejs/plugin-react";
import { resolve } from "path";
export default defineConfig({
plugins: [
react({ include: ["**/*.tsx", "**/*.jsx"] }),
// Conditional plugin
process.env.ANALYZE &&
(await import("rollup-plugin-visualizer")).visualizer(),
].filter(Boolean),
});
For Sass/Tailwind/TypeScript integration, see respective skills:
sass,tailwindcss,typescript.
6. Dev Server
server: {
port: 3000,
strictPort: true, // Fail if port in use
host: true, // Listen on all interfaces
proxy: {
'/api': {
target: 'http://localhost:4000',
changeOrigin: true,
rewrite: p => p.replace(/^\/api/, '')
}
},
cors: true,
hmr: { overlay: true }
}
Rules
- Proxy only for
/apior known backend paths — not/* - CORS enabled by default; configure only if needed
- strictPort prevents silent port conflicts in CI
7. HMR — Hot Module Replacement
Accept HMR in app code
// main.tsx
if (import.meta.hot) {
import.meta.hot.accept("./App", () => {
// Optional: custom update logic
});
}
Rules HMR
- Do not manually manage HMR in library code — Vite handles it
- CSS HMR works automatically via
import.meta.hot.accept()in style imports - Overlay enabled by default (
hmr.overlay: true) — shows errors in browser
8. Environment Variables — import.meta.env
.env files (priority order)
.env # All environments
.env.local # Local overrides (gitignored)
.env.development # Dev only
.env.production # Prod only
Access in code
// Only VITE_* exposed to client
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
Type declarations (vite-env.d.ts)
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string;
readonly VITE_FEATURE_FLAG: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
Rules Environment
- Prefix with
VITE_— only these are exposed to client - Never commit
.env.local— add to.gitignore - Type
ImportMetaEnvinvite-env.d.tsfor IntelliSense
9. import.meta.glob — Glob Imports
Patterns
// Eager: all modules loaded immediately
const modules = import.meta.glob("./components/*.tsx", { eager: true });
// Lazy: dynamic import per module (code splitting)
const modules = import.meta.glob("./pages/**/*.tsx");
// As array
const modules = import.meta.glob("./icons/*.svg", { as: "raw", eager: true });
Rules Glob Imports
- Prefer lazy for routes/pages — enables code splitting
eager: trueonly for small, always-needed collectionsas: 'raw'for text/CSV/SVG;as: 'url'for assets
10. Code Splitting
Manual chunks (vendor separation)
// vite.config.ts
build: {
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom', 'react-router-dom'],
'ui-vendor': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
'utils': ['date-fns', 'zod', 'clsx']
}
}
}
}
Dynamic import (route-level)
// App.tsx
const Dashboard = lazy(() => import("./pages/Dashboard"));
const Settings = lazy(() => import("./pages/Settings"));
Rules Code Splitting
- Vendor chunks for large, stable deps (React, UI libs)
- Route-level lazy for pages — reduces initial bundle
- Avoid over-splitting — too many chunks = more requests
11. Build Optimization
Essential config
build: {
target: 'es2022', // Baseline 2023+ browsers
minify: 'esbuild', // Fast, good compression
cssCodeSplit: true, // Separate CSS files
assetsInlineLimit: 4096, // 4kb inline threshold
modulePreload: { polyfill: true },
reportCompressedSize: true,
rollupOptions: {
output: {
entryFileNames: 'assets/[name]-[hash].js',
chunkFileNames: 'assets/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash].[ext]',
manualChunks: { /* see §10 */ }
}
}
}
Performance rules
| Setting | Value | Why |
|---|---|---|
target |
es2022 |
Modern syntax, smaller output |
minify |
esbuild |
10-20x faster than terser |
cssCodeSplit |
true |
Parallel CSS loading |
modulePreload.polyfill |
true |
Preloads async chunks |
reportCompressedSize |
true |
Accurate gzip/brotli reporting |
For SSR, see
deployskill. For workspaces/monorepos, seepackage-managerskill.
12. TypeScript
Config separation
// tsconfig.json (type-checking)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": true,
"strict": true,
"module": "ESNext",
"moduleResolution": "bundler"
},
"include": ["src/**/*", "vite.config.ts"]
}
// tsconfig.app.json (Vite build)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"noEmit": false,
"outDir": "dist",
"baseUrl": ".",
"paths": { "@/*": ["src/*"] }
}
}
Vite + TypeScript
- Vite transpiles only (via esbuild) — no type checking
- Run
tsc --noEmitseparately — seepackage-managerscripts - Reference: full TS rules in
typescriptskill
13. Methodology
Before using ANY Vite config/plugin/pattern not documented in this skill:
- MCP Context7 (priority):
context7_resolve-library-id+context7_query-docsfor Vite/plugins. - Official docs: vite.dev — verify current config options + plugin API.
- Project config:
vite.config.ts,tsconfig.json,package.json— verify against actual setup. - HARD RULE: If not in this skill AND cannot be verified against 2 authoritative sources → DO NOT USE IT. Document as assumption or risk in report to orchestrator.
14. Prohibitions
- ❌ Do not use
require()in Vite config — ESM only (import) - ❌ Do not commit
dist/or.vite/— add to.gitignore - ❌ Do not use
process.envin client code — useimport.meta.envwithVITE_* - ❌ Do not disable HMR — breaks dev experience
- ❌ Do not inline large assets (>4kb) — bloats JS bundle
- ❌ Do not use experimental plugins without fallback
- ❌ Do not mix CommonJS plugins without
legacyoption - ❌ Do not skip
tsc --noEmitin CI — Vite does not type-check
15. References
Note: For Sass integration, see Sass Note: For Tailwind CSS integration, see Tailwind CSS Note: For TypeScript rules, see TypeScript Note: For SSR/deployment, see Deploy Note: For workspaces/monorepos and package manager conventions, see Package Manager
Last updated: 2026-08