vite
Vite
Platform: Web only. Mobile demos use Expo with Metro bundler. See the expo-sdk skill.
Use Context7 MCP (
resolve-library-idthenquery-docs) for full API reference, plugin ecosystem, and advanced configuration options.
Overview
Build tool and development server for Vite 7.x. Provides instant server start, fast HMR, optimized production builds, and first-class TypeScript support.
Install: pnpm add -D vite
Workflows
Initial setup:
- Create
vite.config.tswith TypeScript types - Install React plugin:
pnpm add -D @vitejs/plugin-react - Configure path aliases for clean imports
- Set up environment variables with
.envfiles - Test dev server:
pnpm vite
Production optimization:
- Configure code splitting and chunk optimization
- Enable build compression (gzip/brotli)
- Run production build:
pnpm vite build - Preview build locally:
pnpm vite preview
Basic Configuration
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
}
},
server: {
port: 5173,
strictPort: true,
open: true,
hmr: { overlay: true },
proxy: {
'/api': { target: 'http://localhost:3000', changeOrigin: true }
}
},
build: {
outDir: 'dist',
sourcemap: true,
minify: 'esbuild',
}
});
Update tsconfig.json paths to match aliases:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"]
}
}
}
React with SWC (faster alternative): pnpm add -D @vitejs/plugin-react-swc, import from @vitejs/plugin-react-swc.
Fast Refresh is enabled by default — no configuration needed.
Environment Variables
# .env - Base config (committed)
VITE_APP_NAME=MyApp
VITE_API_VERSION=v1
# .env.local - Local overrides (gitignored — put secrets here)
VITE_API_URL=http://localhost:3000
# .env.development / .env.production - mode-specific defaults
CRITICAL: All env vars must start with VITE_ to be exposed to client code.
// Access in code
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
const mode = import.meta.env.MODE; // 'development' | 'production'
// Type-safe env vars — add to vite-env.d.ts or src/env.d.ts
interface ImportMetaEnv {
readonly VITE_APP_NAME: string;
readonly VITE_API_URL: string;
}
// Runtime validation
if (!import.meta.env.VITE_API_URL) {
throw new Error('VITE_API_URL is required');
}
Dynamic config with loadEnv:
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
return {
server: { port: Number(env.PORT) || 5173 }
};
});
Build Optimization
Code Splitting
export default defineConfig({
build: {
chunkSizeWarningLimit: 500, // KB
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion'],
},
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
assetFileNames: 'assets/[name]-[hash][extname]',
}
}
}
});
Advanced function-based chunking — use when you need per-view splitting:
manualChunks(id) {
if (id.includes('node_modules')) {
if (id.includes('framer-motion')) return 'vendor-animation';
if (id.includes('react')) return 'vendor-react';
return 'vendor';
}
}
Compression
import { compression } from 'vite-plugin-compression2';
// pnpm add -D vite-plugin-compression2
plugins: [
compression({ algorithm: 'gzip', include: /\.(js|css|html|svg)$/ }),
compression({ algorithm: 'brotliCompress', include: /\.(js|css|html|svg)$/ }),
]
For production-only minification:
minify: isDev ? false : 'terser',
terserOptions: { compress: { drop_console: true, drop_debugger: true } }
CSS and Assets
PostCSS / Tailwind: Point css.postcss to your postcss.config.js. Enable cssCodeSplit: true (default) for large apps.
Asset handling:
// src/assets — processed by Vite (hashed, optimized)
import logo from '@/assets/logo.svg';
// /public — served as-is, NOT processed
<img src="/images/logo.svg" />
// ❌ Never import from public directory
Inline limit: Assets under 4 KB are inlined as base64 by default (assetsInlineLimit: 4096).
Base path for subdirectory hosting: base: '/my-app/'
Vite 7 Notes
- Rolldown — new Rust-based bundler (optional, faster builds)
- Improved TypeScript support and tree-shaking
- Default config works for most projects; advanced bundler options rarely needed
Best Practices
- Use path aliases to avoid
../../../import hell - Prefix client env vars with
VITE_for automatic exposure - Split large vendors into separate chunks for better caching
- Use
.env.localfor secrets — never commit to git - Configure proxy for API calls to avoid CORS in development
- Preview builds before deploying:
pnpm vite build && pnpm vite preview - Use esbuild for faster builds, terser for smaller output
- Set
strictPort: trueto avoid silent port conflicts
Anti-Patterns
- ❌ Forgetting
VITE_prefix on environment variables - ❌ Importing from
/publicdirectory instead ofsrc/assets - ❌ Committing
.env.localwith API keys - ❌ Not configuring path aliases (messy imports)
- ❌ Using terser in development (unnecessary slowdown)
- ❌ Not setting
strictPort(silent port conflicts) - ❌ Ignoring chunk size warnings (impacts load time)
- ❌ Missing
tsconfig.jsonpaths when using aliases - ❌ Hardcoding localhost URLs (use env vars)
- ❌ Placing all vendors in single chunk (defeats caching)
Feedback Loops
Build analysis:
pnpm vite build
# Output shows chunk sizes:
# dist/js/vendor-react-abc123.js 142.34 kB
# dist/js/index-def456.js 87.21 kB
Preview testing:
pnpm vite build && pnpm vite preview
# Verify: all routes work, assets load, no console errors
HMR speed: Should be < 50ms for most updates. Check Chrome DevTools → Network → Filter by "vite".