--- name: Vite description: Configure and optimize Vite for development, production builds, and library bundling. metadata: {"clawdbot":{"emoji":"⚡","requires":{"bins":["node"]},"os":["linux","darwin","win32"]}} --- # Vite Patterns ## Environment Variables - Only `VITE_` prefixed vars are exposed to client code — `DB_PASSWORD` stays server-side, `VITE_API_URL` is bundled - Access via `import.meta.env.VITE_*` not `process.env` — process.env is Node-only and undefined in browser - `.env.local` overrides `.env` and is gitignored by default — use for local secrets - `import.meta.env.MODE` is `development` or `production` — use for conditional logic, not `NODE_ENV` ## CommonJS Compatibility - Pure ESM by default — CommonJS packages need `optimizeDeps.include` for pre-bundling - `require()` doesn't work in Vite — use `import` or `createRequire` from `module` for dynamic requires - Some packages ship broken ESM — add to `ssr.noExternal` or `optimizeDeps.exclude` and let Vite transform them - Named exports from CommonJS may fail — use default import and destructure: `import pkg from 'pkg'; const { method } = pkg` ## Dependency Pre-bundling - Vite pre-bundles dependencies on first run — delete `node_modules/.vite` to force rebuild after package changes - Large dependencies slow down dev server start — add rarely-changing ones to `optimizeDeps.include` for persistent cache - Linked local packages (`npm link`) aren't pre-bundled — add to `optimizeDeps.include` explicitly - `optimizeDeps.force: true` rebuilds every time — only for debugging, kills dev performance ## Path Aliases - Configure in both `vite.config.ts` AND `tsconfig.json` — Vite uses its own, TypeScript uses tsconfig - Use `path.resolve(__dirname, './src')` not relative paths — relative breaks depending on working directory - `@/` alias is not built-in — must configure manually unlike some frameworks ```typescript // vite.config.ts resolve: { alias: { '@': path.resolve(__dirname, './src') } } ``` ## Dev Server Proxy - Proxy only works in dev — production needs actual CORS config or reverse proxy - `changeOrigin: true` rewrites Host header — required for most APIs that check origin - WebSocket proxy needs explicit `ws: true` — HTTP proxy doesn't forward WS by default - Trailing slashes matter: `/api` proxies `/api/users`, `/api/` only proxies `/api//users` ```typescript server: { proxy: { '/api': { target: 'http://localhost:3000', changeOrigin: true, rewrite: path => path.replace(/^\/api/, '') } } } ``` ## Static Assets - `public/` files served at root, not processed — use for favicons, robots.txt, files that need exact paths - `src/assets/` files are processed, hashed, can be imported — use for images, fonts referenced in code - Import assets to get resolved URL: `import logo from './logo.png'` — hardcoded paths break after build - `new URL('./img.png', import.meta.url)` for dynamic paths — template literals with variables don't work ## Build Optimization - `build.rollupOptions.output.manualChunks` for code splitting — without it, one giant bundle - Analyze bundle with `rollup-plugin-visualizer` — find unexpected large dependencies - `build.target` defaults to modern browsers — set `'es2015'` for legacy support, but increases bundle size - `build.cssCodeSplit: true` (default) — each async chunk gets its own CSS file ## Library Mode - `build.lib` for npm packages — different config from app mode - Set `external` for peer dependencies — don't bundle React/Vue into your library - Generate types separately with `tsc` — Vite doesn't emit `.d.ts` files - Both ESM and CJS outputs: `formats: ['es', 'cjs']` — some consumers still need require() ## HMR Issues - Circular imports break HMR — refactor to break the cycle or full reload triggers - State lost on HMR means component isn't accepting updates — check for `import.meta.hot.accept()` - CSS changes trigger full reload if imported in JS that doesn't accept HMR — import CSS in components that do - `server.hmr.overlay: false` hides error overlay — useful for custom error handling but hides issues ## SSR Configuration - `ssr.external` for Node-only packages — prevents bundling node_modules in SSR build - `ssr.noExternal` forces bundling — needed for packages with browser-specific imports - CSS imports fail in SSR by default — use `?inline` suffix or configure `css.postcss` for SSR