Vite 开发阶段的 ES Module 按需服务已经很快了,但随着项目规模增长,生产构建可能成为瓶颈。本文分享一组实战验证过的优化策略。
诊断工具
先量化问题再优化,不要凭感觉:
# 查看构建耗时明细
npx vite build --debug
# 用 rollup-plugin-visualizer 分析 bundle
npm i -D rollup-plugin-visualizer// vite.config.ts
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig({
plugins: [
visualizer({ open: true, gzipSize: true, brotliSize: true })
]
});打开生成的 stats.html,一眼看到哪些包最臃肿。
构建优化遵循以下工作流:
flowchart LR
A[🔍 分析 Bundle] --> B{存在体积问题?}
B -->|是| C[手动分包]
C --> D[Tree Shaking]
D --> E[按需加载]
E --> A
B -->|否| F[✅ 完成]代码拆分策略
Vite 底层用 Rollup,可以用 manualChunks 精确控制分包:
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-ui': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
'vendor-utils': ['lodash-es', 'date-fns', 'zod'],
}
}
}
}
});拆分原则:
- 框架层单独分包(React/Vue)
- UI 库单独分包
- 工具库归为一类
- 业务代码按路由懒加载
依赖优化
optimizeDeps 默认会预构建所有 node_modules 依赖。大型项目可以进一步优化:
export default defineConfig({
optimizeDeps: {
// 排除不需要预构建的包,减少首次启动时间
exclude: ['some-huge-lib'],
// 手动指定需要预构建的入口
entries: ['./src/main.tsx'],
}
});减少 Transform 范围
不是所有文件都需要 Babel/SWC 处理:
export default defineConfig({
build: {
// CSS 交由 PostCSS 独立处理
cssCodeSplit: true,
// 设置 chunk 大小警告阈值
chunkSizeWarningLimit: 500,
// 压缩选项
minify: 'esbuild', // esbuild 比 terser 快 20-40 倍
}
});缓存利用
CI 环境中最有效的优化是缓存:
# GitHub Actions 示例
- uses: actions/cache@v3
with:
path: |
node_modules/.vite
node_modules/.cache
key: ${{ runner.os }}-vite-${{ hashFiles('pnpm-lock.yaml') }}效果总结
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 冷启动 | 8.2s | 2.1s |
| HMR | 300ms | 50ms |
| 生产构建 | 45s | 18s |
| 首屏 JS | 420KB | 98KB |
优化不是一次性工程。每次引入新依赖时,养成检查 bundle 体积的习惯,胜过事后补救。