vite
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseVite
Vite
Platform: Web only. Mobile demos use Expo with Metro bundler. See the expo-sdk skill.
平台: 仅支持Web。移动端演示使用Expo搭配Metro打包工具,请查看expo-sdk技能。
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 viteVite 7.x的构建工具与开发服务器配置方案。提供即时服务器启动、闪电般的HMR(热模块替换)、优化的生产构建,以及对TypeScript的一流支持和丰富的插件生态系统。
安装:
pnpm add -D viteWorkflows
工作流程
Initial setup:
- Create with TypeScript types
vite.config.ts - Install React plugin:
pnpm add -D @vitejs/plugin-react - Configure path aliases for clean imports
- Set up environment variables with files
.env - 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
初始设置:
- 创建带TypeScript类型的文件
vite.config.ts - 安装React插件:
pnpm add -D @vitejs/plugin-react - 配置路径别名以实现清晰的导入
- 使用文件设置环境变量
.env - 测试开发服务器:
pnpm vite
生产构建优化:
- 配置构建输出目录和资源处理规则
- 设置代码分割和chunk优化
- 启用构建压缩(gzip/brotli)
- 配置代码压缩选项
- 执行生产构建:
pnpm vite build - 本地预览构建结果:
pnpm vite preview
Basic Configuration
基础配置
Minimal vite.config.ts
最简vite.config.ts
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
open: true
},
build: {
outDir: 'dist'
}
});typescript
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
支持TypeScript的配置
typescript
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:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}typescript
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')
}
}
});更新tsconfig.json中的路径以匹配:
json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@utils/*": ["./src/utils/*"],
"@types/*": ["./src/types/*"]
}
}
}React Plugin Setup
React插件设置
Basic React Plugin
基础React插件
typescript
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 . No configuration needed.
@vitejs/plugin-reacttypescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
// React的Babel插件(可选)
babel: {
plugins: [
// 在此添加自定义Babel插件
]
}
})
]
});注意: 默认启用Fast Refresh,无需额外配置。
@vitejs/plugin-reactReact with SWC (Faster Alternative)
使用SWC的React配置(更快的替代方案)
typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
export default defineConfig({
plugins: [
react({
// SWC plugins
plugins: [
// Add SWC plugins here
]
})
]
});typescript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
export default defineConfig({
plugins: [
react({
// SWC插件
plugins: [
// 在此添加SWC插件
]
})
]
});Environment Variables
环境变量
.env File Structure
.env文件结构
bash
undefinedbash
undefined.env - Base config (committed)
.env - 基础配置(需提交到版本库)
VITE_APP_NAME=Demo Harness
VITE_API_VERSION=v1
VITE_APP_NAME=Demo Harness
VITE_API_VERSION=v1
.env.local - Local overrides (gitignored)
.env.local - 本地覆盖配置(需加入git忽略)
VITE_API_URL=http://localhost:3000
VITE_API_URL=http://localhost:3000
.env.development - Dev defaults
.env.development - 开发环境默认配置
VITE_DEBUG=true
VITE_API_URL=http://dev.example.com
VITE_DEBUG=true
VITE_API_URL=http://dev.example.com
.env.production - Production defaults
.env.production - 生产环境默认配置
VITE_DEBUG=false
VITE_API_URL=https://api.example.com
**CRITICAL**: All env vars must start with `VITE_` to be exposed to client code.VITE_DEBUG=false
VITE_API_URL=https://api.example.com
**重要提示:** 所有环境变量必须以`VITE_`开头才能在客户端代码中访问。Using Environment Variables
使用环境变量
typescript
// ✅ 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 credentialstypescript
// ✅ 在代码中访问环境变量
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'
// 类型安全的环境变量
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;
}
// ❌ 绝对不要将密钥提交到.env文件中
// 使用.env.local存储API密钥和凭证Configuring Environment Variables
配置环境变量
typescript
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
}
};
});typescript
import { defineConfig, loadEnv } from 'vite';
export default defineConfig(({ mode }) => {
// 根据模式加载对应环境文件
const env = loadEnv(mode, process.cwd(), '');
return {
define: {
// 暴露非VITE_前缀的变量
__APP_VERSION__: JSON.stringify(env.npm_package_version)
},
server: {
port: Number(env.PORT) || 5173
}
};
});Development Server
开发服务器
Basic Server Configuration
基础服务器配置
typescript
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: ['**/.*']
}
}
});typescript
export default defineConfig({
server: {
port: 5173,
strictPort: true, // 如果端口已被占用则退出
open: true, // 服务器启动时自动打开浏览器
cors: true, // 启用CORS
// 热模块替换
hmr: {
overlay: true // 显示错误覆盖层
},
// 文件监听
watch: {
// 忽略点文件
ignored: ['**/.*']
}
}
});Proxy Configuration for API
API代理配置
typescript
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
}
}
}
});typescript
export default defineConfig({
server: {
proxy: {
// 将API请求代理到后端
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// WebSocket代理
'/ws': {
target: 'ws://localhost:3000',
ws: true
},
// 多后端代理
'/v1': {
target: 'http://localhost:3001',
changeOrigin: true
},
'/v2': {
target: 'http://localhost:3002',
changeOrigin: true
}
}
}
});HTTPS Development Server
HTTPS开发服务器
typescript
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')
}
}
});typescript
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
代码分割与Chunk管理
typescript
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
}
});typescript
export default defineConfig({
build: {
rollupOptions: {
output: {
// 手动分割Chunk
manualChunks: {
// 第三方依赖Chunk
'react-vendor': ['react', 'react-dom'],
'router-vendor': ['react-router-dom'],
'animation-vendor': ['framer-motion'],
// 基于功能的Chunk
'dashboard': ['./src/components/views/DashboardView.tsx'],
'reports': ['./src/components/views/ReportsView.tsx']
},
// 资源文件命名
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
},
// Chunk大小警告阈值
chunkSizeWarningLimit: 500, // KB
// 代码压缩
minify: 'esbuild', // 可选值:'terser' | 'esbuild'
// 源映射
sourcemap: true, // 可选值:'inline' | 'hidden'
// 目标浏览器
target: 'esnext', // 可选值:'es2015', 'es2020'等
// CSS代码分割
cssCodeSplit: true
}
});Advanced Chunking Strategy
高级Chunk分割策略
typescript
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()}`;
}
}
}
}
}
});typescript
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 所有node_modules内容放入vendor chunk
if (id.includes('node_modules')) {
// 分割大型依赖
if (id.includes('framer-motion')) {
return 'vendor-animation';
}
if (id.includes('react') || id.includes('react-dom')) {
return 'vendor-react';
}
return 'vendor';
}
// 基于组件的分割
if (id.includes('/components/views/')) {
const viewName = id.split('/components/views/')[1].split('.')[0];
return `view-${viewName.toLowerCase()}`;
}
}
}
}
}
});Compression and Minification
压缩与代码优化
typescript
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
}
}
}
});typescript
import { defineConfig } from 'vite';
import { compression } from 'vite-plugin-compression2';
// 安装:pnpm add -D vite-plugin-compression2
export default defineConfig({
plugins: [
// Gzip压缩
compression({
algorithm: 'gzip',
include: /\.(js|css|html|svg)$/
}),
// Brotli压缩
compression({
algorithm: 'brotliCompress',
include: /\.(js|css|html|svg)$/
})
],
build: {
// esbuild速度更快,terser生成的输出体积更小
minify: 'terser',
terserOptions: {
compress: {
drop_console: true, // 生产环境移除console.log
drop_debugger: true
}
}
}
});CSS and Styling
CSS与样式
PostCSS and Tailwind Integration
PostCSS和Tailwind集成
typescript
// 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";`
}
}
}
});javascript
// postcss.config.js
export default {
plugins: {
'tailwindcss': {},
'autoprefixer': {}
}
};typescript
// vite.config.ts
export default defineConfig({
css: {
postcss: './postcss.config.js',
// CSS Modules配置
modules: {
localsConvention: 'camelCase',
scopeBehaviour: 'local'
},
// 预处理器选项
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`
}
}
}
});javascript
// postcss.config.js
export default {
plugins: {
'tailwindcss': {},
'autoprefixer': {}
}
};CSS Code Splitting
CSS代码分割
typescript
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]';
}
}
}
}
});typescript
export default defineConfig({
build: {
cssCodeSplit: true, // 按Chunk分割CSS
rollupOptions: {
output: {
assetFileNames: (assetInfo) => {
// 整理CSS文件
if (assetInfo.name?.endsWith('.css')) {
return 'css/[name]-[hash][extname]';
}
return 'assets/[name]-[hash][extname]';
}
}
}
}
});Static Assets
静态资源
Asset Handling Patterns
资源处理方式
typescript
// 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';typescript
// 导入资源(返回URL字符串)
import logo from './assets/logo.png';
import styles from './styles.module.css';
// 显式URL导入
import assetUrl from './asset.png?url';
// 原始内容导入
import rawSvg from './icon.svg?raw';
// Worker导入
import Worker from './worker?worker';
// JSON导入
import data from './data.json';Public Directory
公共目录
/public
/images
logo.svg
/fonts
custom-font.woff2
favicon.icotypescript
// 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/public
/images
logo.svg
/fonts
custom-font.woff2
favicon.icotypescript
// 公共目录下的资源会被部署到根路径且不经过处理
// 使用绝对路径引用
<img src="/images/logo.svg" alt="Logo" />
// ❌ 不要从public目录导入
// import logo from '/public/images/logo.svg'; // 错误!
// ✅ 从src/assets导入以进行处理
import logo from '@/assets/logo.svg'; // 正确Asset Configuration
资源配置
typescript
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]';
}
}
}
}
});typescript
export default defineConfig({
// 公共基础路径
base: '/', // 子目录部署时使用'/my-app/'
publicDir: 'public', // 默认值
build: {
assetsDir: 'assets', // 资源输出目录
assetsInlineLimit: 4096, // 小于4kb的资源会被内联为base64
rollupOptions: {
output: {
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]';
}
}
}
}
});Preview Mode
预览模式
Preview Production Build
预览生产构建结果
typescript
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:
bash
undefinedtypescript
export default defineConfig({
preview: {
port: 4173,
strictPort: true,
open: true,
// 代理配置(与开发服务器相同)
proxy: {
'/api': 'http://localhost:3000'
},
// CORS
cors: true,
// 请求头
headers: {
'Cache-Control': 'public, max-age=31536000'
}
}
});命令:
bash
undefinedBuild for production
执行生产构建
pnpm vite build
pnpm vite build
Preview production build locally
本地预览生产构建结果
pnpm vite preview
pnpm vite preview
Preview on specific port
在指定端口预览
pnpm vite preview --port 8080
undefinedpnpm vite preview --port 8080
undefinedVite 7 Notes
Vite 7.x说明
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.
Vite 7.x新增特性:
- Rolldown - 用Rust编写的新打包工具,构建速度更快(可选)
- 改进的TypeScript支持
- 更优的Tree-shaking
- 增强的HMR性能
对于演示项目,默认配置已足够好用,通常不需要高级打包工具选项。
Complete Production Config
完整生产环境配置
typescript
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
}
};
});typescript
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(),
// 生产环境启用压缩(需要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
- 使用路径别名 实现清晰的导入,避免多层相对路径
- 客户端环境变量前缀 使用VITE_以自动暴露到代码中
- 分割大型依赖 为独立的chunk以提升缓存效率
- 生产构建启用压缩(gzip + brotli)
- 使用.env.local 存储密钥,绝对不要提交到版本库
- 配置代理 解决开发环境API请求的CORS问题
- 部署前本地预览构建结果 提前发现问题
- 按类型组织构建输出中的资源 优化CDN缓存
- 生产环境启用源映射 便于调试(或使用'hidden'模式)
- 开发环境用esbuild 提升速度,生产环境用terser减小体积
- 子目录部署时正确设置基础路径
- 配置变更后测试HMR 确保Fast Refresh正常工作
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)
- ❌ 环境变量忘记添加VITE_前缀
- ❌ 从/public目录导入资源而非src/assets
- ❌ 提交包含API密钥的.env.local文件
- ❌ 不配置路径别名(导致导入路径混乱)
- ❌ 开发环境使用terser(不必要的性能损耗)
- ❌ 大型应用禁用CSS代码分割
- ❌ 不设置strictPort(端口冲突无提示)
- ❌ 忽略Chunk大小警告(影响加载速度)
- ❌ 使用别名时未同步tsconfig.json中的路径
- ❌ 硬编码localhost地址(使用环境变量替代)
- ❌ 部署前不测试预览模式
- ❌ 将所有依赖放入单个chunk(失去缓存优势)
- ❌ 演示项目配置代理(演示项目为静态资源,无后端)
Feedback Loops
反馈机制
Dev server performance:
bash
undefined开发服务器性能:
bash
undefinedCheck HMR speed
检查HMR速度
Should be < 50ms for most updates
大多数更新应小于50ms
Chrome DevTools → Network → Filter by "vite"
Chrome开发者工具 → 网络 → 筛选"vite"
**Build analysis:**
```bash
**构建分析:**
```bashAnalyze bundle size
分析包体积
pnpm vite build --mode production
pnpm vite build --mode production
Output shows chunk sizes
输出会显示各个chunk的大小
dist/js/vendor-react-abc123.js 142.34 kB
dist/js/vendor-react-abc123.js 142.34 kB
dist/js/index-def456.js 87.21 kB
dist/js/index-def456.js 87.21 kB
**Preview testing:**
```bash
**预览测试:**
```bashAlways preview before deploying
部署前务必预览
pnpm vite build && pnpm vite preview
pnpm vite build && pnpm vite preview
Test:
测试内容:
- All routes work
- 所有路由正常工作
- Assets load correctly
- 资源加载正常
- API proxy works (if configured)
- API代理正常(如果配置了)
- No console errors
- 控制台无错误
**Environment validation:**
```typescript
// Add runtime checks for required env vars
if (!import.meta.env.VITE_API_URL) {
throw new Error('VITE_API_URL is required');
}
**环境变量验证:**
```typescript—
为必填环境变量添加运行时检查
—
if (!import.meta.env.VITE_API_URL) {
throw new Error('VITE_API_URL是必填项');
}
undefined