Vite 构建优化实战:定位大包、拆分依赖与缓存

Vite 开发环境快,不代表生产包一定小。构建优化的核心不是追求最少文件,而是让首屏只下载必要代码、长期依赖稳定缓存、路由切换没有明显瀑布,并避免重复打包同一依赖。

先看构建事实

生产构建后先记录 Chunk 大小、Gzip/Brotli 大小和首屏请求链。浏览器 Coverage 能帮助判断首屏下载却未执行的代码。可视化工具可以辅助查看依赖组成,但结论仍应回到真实页面加载。

npm run build

如果构建本身慢,使用 Vite 的 Debug 日志和 Node CPU Profile 分辨是插件、转换、压缩还是类型检查:

DEBUG=vite:* npm run build
node --cpu-prof ./node_modules/vite/bin/vite.js build

路由级拆分优先

const routes = [
  {path: '/', component: () => import('./pages/Home.vue')},
  {path: '/editor', component: () => import('./pages/Editor.vue')},
]

富文本编辑器、图表、PDF、地图等依赖应跟随功能页面加载。不要在公共 Barrel 文件中重新导出所有重型模块,否则一个看似轻量的 Import 可能把整个包带回首屏。

手工分包要有边界

manualChunks 适合把稳定且较大的依赖分组,但按每个包名自动拆分可能产生几十个相互依赖的请求。更稳妥的是按能力分组,例如编辑器、图表、后台 UI,而不是把所有 node_modules 都拆成独立文件。

build: {
  rollupOptions: {
    output: {
      manualChunks: {
        editor: ['tiptap-core-package'],
        charts: ['echarts'],
      },
    },
  },
}

示例包名应替换为项目实际依赖。每次调整后检查是否出现循环 Chunk、重复依赖和页面切换额外等待。

缓存依赖而不是缓存错误

文件名 Hash 让浏览器长期缓存静态资源,HTML 则应短缓存或不缓存,保证它能引用最新 Chunk。部署时先上传新静态资源,再切换 HTML;旧资源不要立即删除,否则仍持有旧 HTML 的用户会请求 404。

CI 中缓存包管理器下载目录,避免直接长期缓存 node_modules。Lockfile、Node 版本和平台变化时应自动失效。

开发环境也可能被拖慢

  • 检查会转换大量文件的插件,限制 Include 范围。
  • 避免深层 Barrel Import 导致不必要模块扫描。
  • 大型、兼容性好的 CommonJS 依赖可显式放入依赖预构建。
  • 不要让文件监听覆盖上传目录、日志和构建产物。
  • Type Check 与 Vite Build 可并行,但 CI 必须保留两者结果。

优化验收

  1. 首屏 JS 总量和执行时间是否下降?
  2. 首次路由跳转是否多出串行 Chunk 请求?
  3. 重复访问时静态资源是否正确命中缓存?
  4. 旧页面在发布切换期间是否仍能加载旧 Chunk?
  5. 构建警告是合理的大包,还是可以懒加载的能力?

不要为了消除“大 Chunk 警告”盲目拆包。警告只是入口,用户实际等待时间才是结果。

参考资料