From tenequm-skills
Configure and optimize Vite 7 for React projects. Covers build tooling, dev server, plugins, HMR, chunk splitting, Environment API, and Rolldown integration. Use when setting up Vite, configuring builds, optimizing bundles, managing plugins, or troubleshooting dev server. Triggers on vite, vite config, vite plugin, HMR, dev server, build optimization, chunk splitting, rolldown, vite proxy, environment api, rolldown-vite.
npx claudepluginhub tenequm/skills --plugin gh-cliThis skill uses the workspace's default tool permissions.
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`.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
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.
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 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.
tailwind.config.jsTailwind 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.
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.
Removed in Vite 7. Use build.rollupOptions.output.manualChunks for custom chunk splitting.
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,
},
},
})
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({
babel: {
plugins: [['babel-plugin-react-compiler', {}]],
},
})
Install: pnpm add -D babel-plugin-react-compiler. Auto-memoizes components and hooks - no manual useMemo/useCallback.
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/*"] }
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
}
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
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
File-based route generation for TanStack Router. Must come before react().
import { tanstackRouter } from '@tanstack/router-plugin/vite'
tanstackRouter({ autoCodeSplitting: true })
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)
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'],
},
})
server: {
proxy: {
'/api': {
target: 'http://localhost:8787',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
'/ws': { target: 'ws://localhost:8787', ws: true },
},
}
| 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 },
}
server: {
warmup: {
clientFiles: ['./src/components/*.tsx', './src/routes/__root.tsx'],
},
}
Vite 7 targets baseline-widely-available (Chrome 107+, Edge 107+, Firefox 104+, Safari 16+). Override: build.target: 'es2020' or ['chrome90', 'safari14'].
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'
}
}
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-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.
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.
minify: 'esbuild' but the underlying engine is Oxc)rolldown-vite follows Vite major/minor but patches are independentMost 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.
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.
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.
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))
)
},
}
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.
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
Build produces dist/. Deploy to any static host (Cloudflare Pages, Vercel, Netlify).
tanstackStart({ prerender: { enabled: true, crawlLinks: true } })
react() laststaleTime in dev - avoid unnecessary refetches during HMR reloadsserver.warmup for frequently accessed modulesreact, @tanstack/* into stable chunks for cachingtransition-all - specific properties only for CSS transitionsimport.meta.url for path resolution in ESM config filesrollup-plugin-visualizer before deploysVITE_ prefix discipline - only public values; secrets go in server functionsbuild.sourcemap for production - 'hidden' for error tracking without exposing source