Agent skill
vite
Vite 7.x build tool patterns. Use when configuring build setup, development server, environment variables, asset handling, or optimizing production builds for React applications.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/vite-dralgorhythm-claude-agentic-frame
SKILL.md
Vite
Platform: Web only. Mobile demos use Expo with Metro bundler. See the expo-sdk skill.
Overview
Build tool and development server patterns for Vite 7.x. Provides instant server start, lightning-fast HMR, optimized production builds, and extensive plugin ecosystem with 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 build output directory and asset handling
- Set up code splitting and chunk optimization
- Enable build compression (gzip/brotli)
- Configure minification options
- Run production build:
pnpm vite build - Preview build locally:
pnpm vite preview
Basic Configuration
Minimal vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
open: true
},
build: {
outDir: 'dist'
}
});
TypeScript-Aware Config
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')
}
}
});
Update tsconfig.json paths to match:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}
React Plugin Setup
Basic React Plugin
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
]
}
})
]
});
Note: Fast Refresh is enabled by default in @vitejs/plugin-react. No configuration needed.
React with SWC (Faster Alternative)
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
export default defineConfig({
plugins: [
react({
// SWC plugins
plugins: [
// Add SWC plugins here
]
})
]
});
Environment Variables
.env File Structure
# .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.com
CRITICAL: All env vars must start with VITE_ to be exposed to client code.
Using Environment Variables
// ✅ 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 credentials
Configuring Environment Variables
import { 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
}
};
});
Development Server
Basic Server Configuration
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: ['**/.*']
}
}
});
Proxy Configuration for API
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
}
}
}
});
HTTPS Development Server
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')
}
}
});
Build Optimization
Code Splitting and Chunking
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
}
});
Advanced Chunking Strategy
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()}`;
}
}
}
}
}
});
Compression and Minification
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
}
}
}
});
CSS and Styling
PostCSS and Tailwind Integration
// 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': {}
}
};
CSS Code Splitting
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]';
}
}
}
}
});
Static Assets
Asset Handling Patterns
// 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 Directory
/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'; // Correct
Asset Configuration
export 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]';
}
}
}
}
});
Preview Mode
Preview Production Build
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'
}
}
});
Commands:
# Build for production
pnpm vite build
# Preview production build locally
pnpm vite preview
# Preview on specific port
pnpm vite preview --port 8080
Vite 7 Notes
Vite 7.x introduces:
- Rolldown - New bundler written in Rust for faster builds (optional)
- Improved TypeScript support
- Better tree-shaking
- Enhanced HMR performance
For demos, the default configuration works well. Advanced bundler options are not typically needed.
Complete Production Config
import { 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
}
};
});
Best Practices
- Use path aliases for clean imports and avoid ../../../ hell
- Prefix client env vars with VITE_ for automatic exposure
- Split large vendors into separate chunks for better caching
- Enable compression for production builds (gzip + brotli)
- Use .env.local for secrets and never commit to git
- Configure proxy for API calls to avoid CORS in development
- Preview builds locally before deploying to catch issues
- Organize assets by type in build output for better CDN caching
- Enable sourcemaps in production for debugging (or use 'hidden')
- Use esbuild for faster builds, terser for smaller output
- Set base path correctly for subdirectory deployments
- Test HMR after config changes to ensure Fast Refresh works
Anti-Patterns
- ❌ Forgetting VITE_ prefix on environment variables
- ❌ Importing from /public directory instead of src/assets
- ❌ Committing .env.local with API keys
- ❌ Not configuring path aliases (causes messy imports)
- ❌ Using terser in development (unnecessary slowdown)
- ❌ Disabling CSS code splitting for large apps
- ❌ Not setting strictPort (silent port conflicts)
- ❌ Ignoring chunk size warnings (impacts load time)
- ❌ Missing tsconfig.json paths when using aliases
- ❌ Hardcoding localhost URLs (use env vars)
- ❌ Not testing preview mode before deployment
- ❌ Placing all vendors in single chunk (defeats caching)
- ❌ Configuring proxy for demos (demos are static, no backend)
Feedback Loops
Dev server performance:
# Check HMR speed
# Should be < 50ms for most updates
# Chrome DevTools → Network → Filter by "vite"
Build analysis:
# 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
Preview testing:
# 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
Environment validation:
// Add runtime checks for required env vars
if (!import.meta.env.VITE_API_URL) {
throw new Error('VITE_API_URL is required');
}
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?