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 秒。

相关推荐
原则猫1 小时前
UDP 到底怎么实现可靠的
前端
Java后端的Ai之路1 小时前
14、ReactJS - 路由(Router)
前端·react.js·状态模式
裕晟资质规划2 小时前
三类涉密资质延续时限差异分析:军工60日与集成印制3个月的边界
java·服务器·前端·网络·安全
ShineWinsu2 小时前
对于JavaScript:JavaScript基础语法的解析
开发语言·前端·javascript·面试·web·基础语法·循环
月夏3 小时前
Vue3 转 React:18 项对照表 + 5 个必踩的坑(附 7 天上手路线)
前端
广州华水科技3 小时前
单北斗GNSS位移监测系统的应用与维护解析
前端
梦曦i3 小时前
uni-storage 0.1.0 发布:TTL过期管理+多实例隔离
前端·storage·uni-app x
猫头_4 小时前
AI 流式传输工程指南:模型吐出半截 JSON,前端如何边收边渲染?
前端·javascript·llm
console.log('npc')5 小时前
第 1 章 项目概述与环境搭建
前端·人工智能·大模型
定栓5 小时前
Webpack迁到Vite第七节(二):全家桶移除 — Babel 全家桶深度分析
前端·webpack·node.js