Vite 构建性能调优实战

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.2s2.1s
HMR300ms50ms
生产构建45s18s
首屏 JS420KB98KB

优化不是一次性工程。每次引入新依赖时,养成检查 bundle 体积的习惯,胜过事后补救。