Vite 构建优化:依赖预构建、分包与缓存策略 Vite 构建优化依赖预构建、分包与缓存策略一、构建慢不要先怪工具Vite 的开发体验很快但项目变大后构建和冷启动仍然会慢。依赖过多、组件库引入方式不当、动态导入混乱、产物分包失控都会让构建时间和首屏加载变差。工具不是万能擦屁股纸。项目结构脏换什么构建工具都救不干净。Vite 优化要分开发阶段和生产构建阶段。开发阶段关注冷启动、依赖预构建和 HMR。生产阶段关注 chunk 体积、缓存命中、Tree Shaking 和资源加载顺序。把这两类问题混在一起会导致优化方向错位。比如冷启动慢可能是依赖扫描成本高。生产包大可能是分包策略和按需引入问题。HMR 慢可能是模块边界太粗。每个问题对应的刀不一样别拿一个配置项到处抹。二、构建链路从源码到产物的关键节点flowchart TD A[源码入口] -- B[依赖扫描] B -- C[预构建 optimizeDeps] C -- D[开发服务器] A -- E[Rollup 构建] E -- F[Tree Shaking] F -- G[manualChunks 分包] G -- H[压缩与产物输出] H -- I[浏览器缓存]开发阶段Vite 会扫描入口找到裸模块导入并用 esbuild 做依赖预构建。预构建的意义是把 CommonJS 或多模块依赖转换成 ESM并减少浏览器请求数量。依赖经常变化时预构建缓存会失效冷启动就会变慢。生产构建阶段Vite 底层使用 Rollup。此时重点转向产物结构。业务代码、稳定三方库、路由级页面、图表库、编辑器类重依赖都不应该随便混在一个 chunk 里。分包不只是为了体积更是为了缓存。三、配置示例显式处理重依赖和稳定依赖下面是一个可落地的配置片段。重点是预构建和分包分开处理。import { defineConfig } from vite; import react from vitejs/plugin-react; export default defineConfig({ plugins: [react()], optimizeDeps: { include: [react, react-dom, lodash-es], exclude: [internal/large-dev-only-package], }, build: { sourcemap: false, chunkSizeWarningLimit: 800, rollupOptions: { output: { manualChunks(id) { if (id.includes(node_modules)) { if (id.includes(echarts)) return vendor-echarts; if (id.includes(monaco-editor)) return vendor-editor; if (id.includes(react)) return vendor-react; return vendor; } }, }, }, }, });optimizeDeps.include适合把常用依赖提前纳入预构建减少开发阶段抖动。manualChunks则服务于生产缓存。React 这类稳定依赖可以单独拆出来图表库和编辑器也应该独立。这样业务发版时不会让所有大依赖缓存一起失效。还要配合包引入方式。组件库如果不支持 Tree Shaking必须按需引入或使用插件处理。否则分包再漂亮也只是把一大坨无用代码换个文件名。四、权衡分析分包过细会增加请求与调度成本分包不是越细越好。HTTP/2 能缓解多请求成本但浏览器仍然要调度、解析和执行 JS。过多 chunk 会增加瀑布复杂度尤其在移动端弱网下不一定划算。分包策略要结合路由、缓存和首屏。预构建也不是越多越好。把不常用依赖都 include 进去会增加冷启动成本和缓存体积。只应显式 include 高频且扫描不稳定的依赖。构建优化必须用数据闭环。建议记录构建耗时、产物体积、首屏资源数量、缓存命中率。不要只看一次本地 build。CI 环境、开发机和线上网络条件都可能不同。生产落地补充从能跑到可维护从生产落地角度看这类方案不能只停留在主流程。更关键的是把输入校验、失败分支、资源上限和回滚路径提前写清楚。主流程通常容易在演示环境里跑通真正暴露问题的是异常输入、依赖抖动、并发放大和权限边界。一篇技术方案如果没有解释这些约束读者很难判断它能否放进真实系统。评估时建议先定义三类指标正确性指标、稳定性指标和成本指标。正确性指标回答结果是否可信稳定性指标回答失败时是否可控成本指标回答持续运行是否划算。三类指标要同时进入验收清单不能只用平均耗时或单次成功率证明方案有效。异常路径补充把失败当成接口契约下面的补充片段强调一个原则调用方必须得到稳定、可解释的错误而不是在超时、空输入或依赖失败时收到模糊结果。代码不追求覆盖所有业务细节而是展示输入校验、超时控制和错误封装这三个生产系统最容易遗漏的环节。type GuardedResultT { ok: true; data: T } | { ok: false; error: string }; async function runWithGuardT(task: () PromiseT, timeoutMs 3000): PromiseGuardedResultT { const controller new AbortController(); const timer setTimeout(() controller.abort(), timeoutMs); try { const data await task(); return { ok: true, data }; } catch (error) { const message error instanceof Error ? error.message : unknown error; return { ok: false, error: message }; } finally { clearTimeout(timer); } }五、总结Vite 优化要分清开发阶段和生产阶段。开发阶段关注依赖预构建和 HMR 边界生产阶段关注分包、Tree Shaking 和缓存。不要用一个配置项解决所有问题。落地建议是先分析构建产物再识别重依赖和缓存边界。稳定三方库单独分包路由级模块懒加载组件库按需引入。构建工具能加速干净结构但不能替混乱架构背锅。