Vite 构建缓存优化:二次构建从 15s 降到 2s 的实战方案

问题场景

一个中型 Vue3 + TS 项目(约 200 个页面),CI/CD 流程中每次 npm run build 耗时 15-25 秒。团队每天合并 20+ PR,每次合并都要重跑一遍构建,流水线排队严重。更糟的是,50% 的改动只是改了一个文案或样式,却要全量重新打包,浪费大量算力和时间。

原因分析

Vite 开发模式基于 esbuild + 浏览器原生 ESM,快得飞起。但生产构建走的是 Rollup 的完整打包流程:

  1. 没有利用缓存 ------ 默认情况下 Vite/Rollup 不持久化缓存
  2. 重复包体积计算 ------ 每次构建都对 node_modules 中的依赖重新 tree-shake
  3. chunk 文件名每次都变 ------ 即使代码没改,hash 变了,CDN 缓存失效

解决方案

方案一:Vite 缓存插件------让构建结果可复用

安装 vite-plugin-cache 插件,它会在构建时生成 .vite-cache 目录,下次构建时跳过未改动文件的 bundle 过程。

bash 复制代码
npm i -D vite-plugin-cache
ts 复制代码
// vite.config.ts
import { viteCache } from 'vite-plugin-cache'

export default defineConfig({
  plugins: [
    vue(),
    viteCache({
      cacheDir: '.vite-cache',
      // 排除有副作用的入口文件
      exclude: ['src/main.ts'],
    }),
  ],
})

效果:未改动模块直接复用 cache,二次构建时间减少 60%-70%

方案二:手动缓存 Rollup 构建产物(CI 场景)

在 CI 中持久化 Rollup 的 chunk 信息,利用 output.manualChunks第三方依赖打成一个稳定 chunk。

ts 复制代码
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks(id) {
          // 把 node_modules 中的依赖按包名分组
          if (id.includes('node_modules')) {
            // 大包拆成独立 chunk,减小变化传播面
            if (id.includes('vue')) return 'vendor-vue'
            if (id.includes('echarts') || id.includes('antv')) return 'vendor-charts'
            if (id.includes('lodash')) return 'vendor-libs'
            return 'vendor-others'
          }
        },
        // 关键:内容不变则 hash 不变
        entryFileNames: 'assets/[name]-[hash].js',
        chunkFileNames: 'assets/[name]-[hash].js',
      },
    },
  },
})

配合 CI 的缓存策略(GitHub Actions 的 actions/cache):

yaml 复制代码
- uses: actions/cache@v3
  with:
    path: |
      node_modules
      **/.vite-cache
    key: ${{ runner.os }}-vite-${{ hashFiles('yarn.lock') }}

效果:依赖包没变 → vendor chunk hash 不变 → CDN 复用旧文件 → 用户无需重新下载。

方案三:用 esbuild 替代 terser 做 minify

ts 复制代码
export default defineConfig({
  build: {
    minify: 'esbuild', // 默认 terser,改为 esbuild
    // terser 慢但体积小一点,esbuild 快但体积大 5%-10%
    // 对于非极端场景,esbuild 完全够用
  },
})

对比数据(实测 200 页面项目):

方案 首次构建 二次构建(改 1 个文件) 备注
默认配置 18s 18s 每次全量
+ manualChunks 16s 16s 依赖稳定
+ vite-plugin-cache 15s 4.2s 模块级缓存
+ esbuild minify 12s 2.1s 组合最优

方案四:增量构建跑单元测试而非全量构建

还有一个常见的误区------很多团队在 CI 里跑完构建才跑测试。改为:

  1. vitest 跑单测(不需要构建)
  2. 检查 git diff,只对改动文件跑 E2E
  3. 最终只构建一次产物
bash 复制代码
# CI 中这样跑,节省构建次数
npx vitest run --changed  # 只跑改动文件相关的测试

要点总结

手段 收益 落地成本
vite-plugin-cache 降 60%+ 构建时间 加 1 行插件
manualChunks 拆包 稳定性 + CDN 复用 30 行配置
esbuild minify 快 5-8 倍压缩 改一个参数
CI 缓存 跳过 node_modules 下载 标准 GitHub Action

最佳实践组合manualChunks 分 vendor + vite-plugin-cache 做增量 + esbuild 做 minify + CI 缓存 node_modules,一套下来二次构建平均 2-3 秒

相关推荐
谢慧琼44 分钟前
2026零基础做企业网站,低成本搭建官方网站
服务器·前端·javascript
weixin_431600442 小时前
前端数据埋点(1):一次点击如何变成一条埋点
前端·js·数据埋点
IT_陈寒2 小时前
Python线程池吞了异常还不告诉我,这谁顶得住啊
前端·人工智能·后端
计算机魔术师2 小时前
同样是AI辅助建造,为什么有的游戏三个月就烂尾了?
前端
用户921080262863 小时前
0. 做 Agent 产品,前端 AI 组件框架怎么选?
前端
拾年2753 小时前
React Hooks 进阶篇:useMemo / useCallback / useReducer / useImperativeHandle,用「算账 +
前端·javascript·react.js
Jackson__4 小时前
面试官:如何在老项目中使用新框架,并实现通信?
前端·javascript·面试
拾年2754 小时前
React Hooks 保姆级教程:把组件想象成失忆的打工人,4 个 Hook 带你原地起飞
前端·javascript·react.js
mmsx4 小时前
一个 Bug 修了 12 轮,根因只有一句话:AI 编程时代,日志才是唯一的真相
前端
默_笙4 小时前
😝 5 亿次循环卡死页面?我用 Web Worker 把它扔进后台线程,页面丝滑如初
前端·javascript