vite
Vite 7
Build tooling and dev server for React projects. Vite 7 (June 2025) is ESM-only, requires Node.js 20.19+ / 22.12+, and defaults browser target to baseline-widely-available. The user's stack uses rolldown-vite (Rust-based drop-in replacement), @vitejs/plugin-react, @tailwindcss/vite, @tanstack/router-plugin, @cloudflare/vite-plugin, and @tanstack/react-start.
Critical Rules
Plugin Order Matters
TanStack Start or TanStack Router plugin MUST come before @vitejs/plugin-react:
plugins: [
tanstackStart(), // or tanstackRouter() for SPA
tailwindcss(),
react(), // ALWAYS last among framework plugins
]
Wrong order causes route generation failures and HMR breakage.
Vite 7 is ESM-Only
Vite 7 distributes as ESM only. Your vite.config.ts must use import/export syntax. CJS require() is not supported in config files. Node.js 20.19+ supports require(esm) natively, so Vite can still be required by CJS consumers.
No tailwind.config.js
Tailwind CSS v4 uses CSS-first configuration. Never create tailwind.config.js/tailwind.config.ts. Use @tailwindcss/vite plugin and configure in CSS via @theme, @utility, @plugin.
Environment Variables Need VITE_ Prefix
Only variables prefixed with VITE_ are exposed to client code via import.meta.env. Server-only secrets must NOT use this prefix. For type safety, augment ImportMetaEnv in vite-env.d.ts.
splitVendorChunkPlugin Is Removed
Removed in Vite 7. Use build.rollupOptions.output.manualChunks for custom chunk splitting.
Configuration
vite.config.ts (Full Stack with TanStack Start)
import { defineConfig } from 'vite'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
import { cloudflare } from '@cloudflare/vite-plugin'
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tanstackStart(),
cloudflare(),
tailwindcss(),
react(),
],
resolve: {
alias: {
'@': new URL('./src', import.meta.url).pathname,
},
},
})
vite.config.ts (SPA with TanStack Router)
import { defineConfig } from 'vite'
import { tanstackRouter } from '@tanstack/router-plugin/vite'
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [
tanstackRouter({ autoCodeSplitting: true }),
tailwindcss(),
react(),
],
resolve: {
alias: {
'@': new URL('./src', import.meta.url).pathname,
},
},
})
React Compiler
react({
babel: {
plugins: [['babel-plugin-react-compiler', {}]],
},
})
Install: pnpm add -D babel-plugin-react-compiler. Auto-memoizes components and hooks - no manual useMemo/useCallback.
Path Aliases
Use import.meta.url for ESM-compatible resolution (no __dirname in ESM):
resolve: {
alias: {
'@': new URL('./src', import.meta.url).pathname,
},
}
Mirror in tsconfig.json: "paths": { "@/*": ["./src/*"] }
Environment Variables
Files: .env, .env.local, .env.[mode], .env.[mode].local. Only VITE_-prefixed vars exposed to client. Built-in constants: import.meta.env.MODE, .DEV, .PROD, .SSR, .BASE_URL.
Type augmentation in src/vite-env.d.ts:
interface ImportMetaEnv {
readonly VITE_API_URL: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
Plugin Ecosystem
@vitejs/plugin-react
Provides Fast Refresh (HMR for React), JSX transform, and optional Babel plugin pipeline. Always place last among framework plugins.
import react from '@vitejs/plugin-react'
react() // zero-config default
react({ fastRefresh: false }) // disable for debugging HMR issues
@tailwindcss/vite
Native Vite integration for Tailwind CSS v4. Replaces PostCSS-based setup - no postcss.config.js needed.
import tailwindcss from '@tailwindcss/vite'
tailwindcss() // zero-config, reads @theme from CSS
@tanstack/router-plugin/vite
File-based route generation for TanStack Router. Must come before react().
import { tanstackRouter } from '@tanstack/router-plugin/vite'
tanstackRouter({ autoCodeSplitting: true })
@tanstack/react-start/plugin/vite
Full-stack plugin for TanStack Start. Includes router plugin internally - do NOT add both.
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
tanstackStart() // default SSR
tanstackStart({ spa: { enabled: true } }) // SPA mode (no SSR)
@cloudflare/vite-plugin
Runs Worker code inside workerd during dev, matching production behavior. Uses Vite's Environment API for runtime integration.
import { cloudflare } from '@cloudflare/vite-plugin'
cloudflare() // reads wrangler.jsonc by default
// Programmatic config (no wrangler file needed)
cloudflare({
config: {
name: 'my-worker',
compatibility_flags: ['nodejs_compat'],
},
})
Dev Server
Proxy Configuration
server: {
proxy: {
'/api': {
target: 'http://localhost:8787',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/ws': { target: 'ws://localhost:8787', ws: true },
},
}
HMR Troubleshooting
| Symptom | Fix |
|---|---|
| Full reload instead of HMR | Check plugin-react is loaded |
| HMR not connecting | Set server.hmr.clientPort if behind reverse proxy |
| Stale state after edit | Component must export a single component |
| CSS not updating | Ensure @tailwindcss/vite is in plugins |
Behind a reverse proxy:
server: {
hmr: { protocol: 'ws', host: 'localhost', port: 5173, clientPort: 443 },
}
File Warmup
server: {
warmup: {
clientFiles: ['./src/components/*.tsx', './src/routes/__root.tsx'],
},
}
Build Optimization
Default Browser Target
Vite 7 targets baseline-widely-available (Chrome 107+, Edge 107+, Firefox 104+, Safari 16+). Override: build.target: 'es2020' or ['chrome90', 'safari14'].
Manual Chunks
build: {
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'tanstack': ['@tanstack/react-router', '@tanstack/react-query'],
},
},
},
}
Dynamic splitting by function:
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('react')) return 'react-vendor'
if (id.includes('@tanstack')) return 'tanstack'
return 'vendor'
}
}
Bundle Analysis
pnpm add -D rollup-plugin-visualizer
import { visualizer } from 'rollup-plugin-visualizer'
// Add to plugins array
visualizer({ filename: 'stats.html', open: true, gzipSize: true })
See build-optimization.md for detailed chunking strategies, CSS splitting, asset inlining, source maps, and performance tuning.
Rolldown Integration
What is rolldown-vite
rolldown-vite is a Rust-based drop-in replacement for Vite's bundler, developed by the Vite team (sponsored by VoidZero). It replaces both esbuild and Rollup with a single high-performance tool built on Rolldown and the Oxc toolkit. Build time reductions of 3x to 16x have been reported, with memory usage cut by up to 100x on large projects.
Rolldown will become the default bundler in Vite 8 (currently in beta). Using rolldown-vite today prepares your project for the transition.
Note: Vite 7 requires Vitest 3.2+ for compatibility. Earlier Vitest versions will not work.
Installation
In package.json, alias vite to rolldown-vite:
{
"devDependencies": {
"vite": "npm:rolldown-vite@latest"
}
}
For monorepos or frameworks with Vite as a peer dependency, use overrides:
{
"pnpm": {
"overrides": {
"vite": "npm:rolldown-vite@latest"
}
}
}
Then run pnpm install. No config changes needed - it is a drop-in replacement.
Key Differences from Standard Vite
- No esbuild dependency - Oxc handles all transforms and minification (config still shows
minify: 'esbuild'but the underlying engine is Oxc) - Faster builds - Rust-native bundling, especially for large projects
- Same plugin API - Rollup/Vite plugins work without changes in most cases
- Patch versions may break -
rolldown-vitefollows Vite major/minor but patches are independent
Compatibility Notes
Most frameworks and Vite plugins work out of the box. Check the rolldown-vite repo for known issues and changelog. Some warnings about unsupported options may appear during the transition period.
Environment API
Experimental API introduced in Vite 6, improved in Vite 7 with the buildApp hook. Enables multi-target builds (browser, Node.js, edge runtimes) from a single Vite config.
How It Works
Each environment has its own module graph, plugin pipeline, and build config. The @cloudflare/vite-plugin uses this to run Worker code inside workerd during dev, matching production behavior.
buildApp Hook (Vite 7)
Frameworks coordinate building multiple environments. Config-level form (most common):
export default defineConfig({
builder: {
async buildApp(builder) {
await builder.build(builder.environments.client)
await builder.build(builder.environments.server)
},
},
})
Plugin hook form (for plugin authors):
{
name: 'my-framework',
buildApp: async (builder) => {
const environments = Object.values(builder.environments)
return Promise.all(
environments.map((env) => builder.build(env))
)
},
}
Multi-Environment Config
export default defineConfig({
environments: {
client: {
build: { outDir: 'dist/client' },
},
server: {
build: { outDir: 'dist/server' },
},
},
})
For most projects, the @cloudflare/vite-plugin or @tanstack/react-start handles environment configuration automatically. Direct Environment API usage is for framework authors.
Deployment
Cloudflare Workers (via TanStack Start)
Add cloudflare() to plugins and create wrangler.jsonc:
// wrangler.jsonc
{
"name": "my-app",
"compatibility_date": "2025-01-01",
"compatibility_flags": ["nodejs_compat"],
"main": "./dist/server/index.js",
"assets": { "directory": "./dist/client" }
}
pnpm vite build && pnpm wrangler deploy
Static SPA
Build produces dist/. Deploy to any static host (Cloudflare Pages, Vercel, Netlify).
Prerendering (SSG)
tanstackStart({ prerender: { enabled: true, crawlLinks: true } })
Best Practices
- Plugin order - framework plugins first, then utilities, then
react()last - Use rolldown-vite - drop-in replacement with 3-16x faster builds
- Set
staleTimein dev - avoid unnecessary refetches during HMR reloads - Warm up critical files - use
server.warmupfor frequently accessed modules - Split vendor chunks - separate
react,@tanstack/*into stable chunks for caching - Never use
transition-all- specific properties only for CSS transitions - Use
import.meta.urlfor path resolution in ESM config files - Analyze bundles regularly - use
rollup-plugin-visualizerbefore deploys - Keep
VITE_prefix discipline - only public values; secrets go in server functions - Set
build.sourcemapfor production -'hidden'for error tracking without exposing source
Resources
- Vite Docs: https://vite.dev/guide/
- Vite 7 Blog: https://vite.dev/blog/announcing-vite7
- Migration Guide: https://vite.dev/guide/migration
- Build Options: https://vite.dev/config/build-options
- Server Options: https://vite.dev/config/server-options
- Env Variables: https://vite.dev/guide/env-and-mode
- Rolldown-Vite: https://voidzero.dev/posts/announcing-rolldown-vite
- Cloudflare Vite Plugin: https://developers.cloudflare.com/workers/vite-plugin/
- Plugin React: https://github.com/vitejs/vite-plugin-react
- GitHub: https://github.com/vitejs/vite
More from tenequm/skills
swift-macos
Comprehensive macOS app development with Swift 6.2, SwiftUI, SwiftData, Swift Concurrency, Foundation Models, Swift Testing, ScreenCaptureKit, and app distribution. Use when building native Mac apps, implementing windows/scenes/navigation/menus/toolbars, SwiftData models and queries, modern concurrency, on-device AI, testing, screen/audio capture, menu bar apps, AppKit bridges, login items, process monitoring, or App Store and Developer ID distribution. Triggers on macOS app, SwiftUI macOS, SwiftData, Swift concurrency, Foundation Models, Swift Testing, ScreenCaptureKit, screen capture, screen recording, AVFoundation, MenuBarExtra, NSViewRepresentable, notarize, login item, and process monitoring.
56react-typescript
Build React 19 applications with TypeScript. Covers Actions, Activity, use() hook, React Compiler, ref-as-prop, useEffectEvent, and strict TypeScript patterns. Use when creating components, managing state, typing props, handling events, using hooks, or working with React 19 features. Triggers on react, typescript, tsx, component types, hook types, react 19, react compiler, actions, use hook, useEffectEvent, activity, import defer.
47shadcn-tailwind
Build UIs with Tailwind CSS v4 and shadcn/ui. Covers CSS variables with OKLCH colors, component variants with CVA, responsive design, dark mode, and Tailwind v4.2 features. Supports Radix UI and Base UI primitives, CLI 3.0, and visual styles. Use when building interfaces with Tailwind, styling shadcn/ui components, implementing themes, or working with utility-first CSS. Triggers on tailwind, shadcn, utility classes, CSS variables, OKLCH, component styling, theming, dark mode, radix ui.
39python-dev
Opinionated Python development setup with uv + ty + ruff + pytest + just. Use when creating new Python projects, setting up pyproject.toml, configuring linting, type checking, testing, or build tooling. Triggers on "python project", "uv init", "pyproject.toml", "ruff config", "ty check", "pytest setup", "justfile", "python linting", "python formatting", "type checking python".
39privy-integration
Integrates Privy authentication, embedded wallets, and agent payment protocols into web and agentic apps. Covers React SDK (PrivyProvider, hooks, wagmi), Node.js SDK, smart wallets (ERC-4337), x402 and MPP machine payments, Tempo chain, and agentic wallets with policies. Use when setting up Privy auth, creating embedded or agentic wallets, adding x402 or MPP payments, integrating with Tempo, configuring wallet policies, or connecting Privy to MCP/Agent Auth flows.
36biome
Lint and format frontend code with Biome 2.4. Covers type-aware linting, GritQL custom rules, domains, import organizer, and migration from ESLint/Prettier. Use when configuring linting rules, formatting code, writing custom lint rules, or setting up CI checks. Triggers on biome, biome config, biome lint, biome format, biome check, biome ci, gritql, migrate from eslint, migrate from prettier, import sorting, code formatting, lint rules, type-aware linting, noFloatingPromises.
34