Loading...
Loading...
Vite 7.x build tool patterns. Use when configuring build setup, development server, environment variables, asset handling, or optimizing production builds for React applications.
npx skill4agent add nguyenhuuca/assessment vitePlatform: Web only. Mobile demos use Expo with Metro bundler. See the expo-sdk skill.
pnpm add -D vitevite.config.tspnpm add -D @vitejs/plugin-react.envpnpm vitepnpm vite buildpnpm vite previewimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
open: true
},
build: {
outDir: 'dist'
}
});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'),
'@types': path.resolve(__dirname, './src/types')
}
}
});{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
// Babel plugins for React (optional)
babel: {
plugins: [
// Add custom babel plugins here
]
}
})
]
});@vitejs/plugin-reactimport { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
export default defineConfig({
plugins: [
react({
// SWC plugins
plugins: [
// Add SWC plugins here
]
})
]
});# .env - Base config (committed)
VITE_APP_NAME=Demo Harness
VITE_API_VERSION=v1
# .env.local - Local overrides (gitignored)
VITE_API_URL=http://localhost:3000
# .env.development - Dev defaults
VITE_DEBUG=true
VITE_API_URL=http://dev.example.com
# .env.production - Production defaults
VITE_DEBUG=false
VITE_API_URL=https://api.example.comVITE_// ✅ Accessing env vars 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
interface ImportMetaEnv {
readonly VITE_APP_NAME: string;
readonly VITE_API_URL: string;
readonly VITE_API_VERSION: string;
readonly VITE_DEBUG: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
// ❌ NEVER commit secrets to .env files
// Use .env.local for API keys and credentialsimport { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// Load env file based on mode
const env = loadEnv(mode, process.cwd(), '');
return {
define: {
// Expose non-VITE_ prefixed vars
__APP_VERSION__: JSON.stringify(env.npm_package_version)
},
server: {
port: Number(env.PORT) || 5173
}
};
});export default defineConfig({
server: {
port: 5173,
strictPort: true, // Exit if port is already in use
open: true, // Open browser on server start
cors: true, // Enable CORS
// Hot Module Replacement
hmr: {
overlay: true // Show error overlay
},
// File watching
watch: {
// Ignore dotfiles
ignored: ['**/.*']
}
}
});export default defineConfig({
server: {
proxy: {
// Proxy API requests to backend
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// WebSocket proxy
'/ws': {
target: 'ws://localhost:3000',
ws: true
},
// Multiple backends
'/v1': {
target: 'http://localhost:3001',
changeOrigin: true
},
'/v2': {
target: 'http://localhost:3002',
changeOrigin: true
}
}
}
});import { defineConfig } from 'vite';
import fs from 'node:fs';
export default defineConfig({
server: {
https: {
key: fs.readFileSync('./.cert/key.pem'),
cert: fs.readFileSync('./.cert/cert.pem')
}
}
});export default defineConfig({
build: {
rollupOptions: {
output: {
// Manual chunk splitting
manualChunks: {
// Vendor chunks
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion'],
// Feature-based chunks
'dashboard': ['./src/components/views/DashboardView.tsx'],
'reports': ['./src/components/views/ReportsView.tsx']
},
// Asset file naming
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
// Chunk size warnings
chunkSizeWarningLimit: 500, // KB
// Minification
minify: 'esbuild', // 'terser' | 'esbuild'
// Source maps
sourcemap: true, // or 'inline' | 'hidden'
// Target browsers
target: 'esnext', // or 'es2015', 'es2020', etc.
// CSS code splitting
cssCodeSplit: true
}
});export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// All node_modules in vendor chunk
if (id.includes('node_modules')) {
// Split large vendors
if (id.includes('framer-motion')) {
return 'vendor-animation';
}
if (id.includes('react') || id.includes('react-dom')) {
return 'vendor-react';
}
return 'vendor';
}
// Component-based splitting
if (id.includes('/components/views/')) {
const viewName = id.split('/components/views/')[1].split('.')[0];
return `view-${viewName.toLowerCase()}`;
}
}
}
}
}
});import { defineConfig } from 'vite';
import { compression } from 'vite-plugin-compression2';
// Install: pnpm add -D vite-plugin-compression2
export default defineConfig({
plugins: [
// Gzip compression
compression({
algorithm: 'gzip',
include: /\.(js|css|html|svg)$/
}),
// Brotli compression
compression({
algorithm: 'brotliCompress',
include: /\.(js|css|html|svg)$/
})
],
build: {
// esbuild is faster, terser produces smaller output
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // Remove console.log in production
drop_debugger: true
}
}
}
});// vite.config.ts
export default defineConfig({
css: {
postcss: './postcss.config.js',
// CSS modules configuration
modules: {
localsConvention: 'camelCase',
scopeBehaviour: 'local'
},
// Preprocessor options
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
}
});// postcss.config.js
export default {
plugins: {
'tailwindcss': {},
'autoprefixer': {}
}
};export default defineConfig({
build: {
cssCodeSplit: true, // Split CSS per chunk
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
// Organize CSS files
if (assetInfo.name?.endsWith('.css')) {
return 'css/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});// Importing assets (returns URL string)
import logo from './assets/logo.png';
import styles from './styles.module.css';
// Explicit URL imports
import assetUrl from './asset.png?url';
// Raw content import
import rawSvg from './icon.svg?raw';
// Worker import
import Worker from './worker?worker';
// JSON import
import data from './data.json';/public
/images
logo.svg
/fonts
custom-font.woff2
favicon.ico// Public assets are served at root and NOT processed
// Reference with absolute path
<img src="/images/logo.svg" alt="Logo" />
// ❌ Don't import from public
// import logo from '/public/images/logo.svg'; // Wrong!
// ✅ Import from src/assets for processing
import logo from '@/assets/logo.svg'; // Correctexport default defineConfig({
// Public base path
base: '/', // or '/my-app/' for subdirectory hosting
publicDir: 'public', // Default
build: {
assetsDir: 'assets', // Output directory for assets
assetsInlineLimit: 4096, // Inline assets < 4kb as base64
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
// Organize by file type
if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
return 'images/[name]-[hash][extname]';
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return 'fonts/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});export default defineConfig({
preview: {
port: 4173,
strictPort: true,
open: true,
// Proxy config (same as dev server)
proxy: {
'/api': 'http://localhost:3000'
},
// CORS
cors: true,
// Headers
headers: {
'Cache-Control': 'public, max-age=31536000'
}
}
});# Build for production
pnpm vite build
# Preview production build locally
pnpm vite preview
# Preview on specific port
pnpm vite preview --port 8080import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { compression } from 'vite-plugin-compression2';
import path from 'node:path';
export default defineConfig(({ mode }) => {
const isDev = mode === 'development';
return {
plugins: [
react(),
// Compression for production (requires vite-plugin-compression2)
!isDev && compression({ algorithm: 'gzip', include: /\.(js|css|html|svg)$/ }),
!isDev && compression({ algorithm: 'brotliCompress', include: /\.(js|css|html|svg)$/ })
].filter(Boolean),
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@types': path.resolve(__dirname, './src/types')
}
},
server: {
port: 5173,
strictPort: true,
open: true,
hmr: {
overlay: true
},
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist',
sourcemap: !isDev,
minify: isDev ? false : 'terser',
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
},
rollupOptions: {
output: {
manualChunks: {
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion']
},
assetFileNames: (assetInfo) => {
const info = assetInfo.name.split('.');
const ext = info[info.length - 1];
if (/png|jpe?g|svg|gif|webp|ico/i.test(ext)) {
return 'images/[name]-[hash][extname]';
}
if (/woff2?|ttf|otf|eot/i.test(ext)) {
return 'fonts/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
},
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
chunkSizeWarningLimit: 500
},
preview: {
port: 4173,
strictPort: true,
open: true
}
};
});# Check HMR speed
# Should be < 50ms for most updates
# Chrome DevTools → Network → Filter by "vite"# Analyze bundle size
pnpm vite build --mode production
# Output shows chunk sizes
# dist/js/vendor-react-abc123.js 142.34 kB
# dist/js/index-def456.js 87.21 kB# Always preview before deploying
pnpm vite build && pnpm vite preview
# Test:
# - All routes work
# - Assets load correctly
# - API proxy works (if configured)
# - No console errors// Add runtime checks for required env vars
if (!import.meta.env.VITE_API_URL) {
throw new Error('VITE_API_URL is required');
}