manualchunks 是 vite 中精细化代码分包的核心配置,支持对象(适用于明确第三方库)和函数(适用于路径规则、动态判断)两种写法;需注意匹配顺序、避免碎片化与循环依赖,并结合构建产物验证效果。

在 Vite 中,build.rollupOptions.output.manualChunks 是实现精细化代码分包的核心配置项,它直接对接 Rollup 的 chunk 生成逻辑,允许你按模块路径、依赖关系或业务语义完全控制哪些代码被打进哪个包。关键不在于“写对语法”,而在于理解匹配逻辑和避免常见陷阱。
明确 manualChunks 的两种写法及适用场景
它支持对象和函数两种形式,用途差异明显:
-
对象写法(适合明确依赖名的第三方库):直接声明包名与模块数组的映射,Vite 会把列表中每个模块及其所有依赖(递归)打包进同名 chunk。
例如:{ echarts: ['echarts'], vue: ['vue', 'vue-router', '@vueuse/core'] }—— 简洁、可读性强,但无法处理路径模糊匹配或条件逻辑。 -
函数写法(适合路径规则、动态判断):接收模块绝对路径
id,返回字符串即 chunk 名。它更灵活,能识别node_modules/xxx、src/utils/或甚至文件后缀。
例如:id => id.includes('node_modules/axios') ? 'axios' : null—— 适合拆分特定库、按目录聚类、排除某些模块等复杂策略。
拆分 ECharts 并隔离于 vendor 的典型配置
默认情况下,Vite 会把所有 node_modules 打进 vendor,但若想单独拎出 echarts(比如因体积大、更新频次低、需 CDN 加载),必须同时做两件事:
- 用
external: ['echarts']告诉 Rollup 完全不打包它(需确保运行时全局存在或通过 script 引入); - 或不用
external,改用manualChunks函数精准拦截:if (id.includes('node_modules/echarts')) return 'echarts'; - 再补一条规则,把其余
node_modules归入vendor:if (id.includes('node_modules')) return 'vendor'; - 注意顺序:函数内判断要从具体到宽泛,否则
echarts会被node_modules规则提前捕获。
按业务模块或目录结构自动聚类分包
比起硬编码依赖名,按项目结构分包更可持续。例如把所有 src/modules/report/ 下的代码(含组件、工具、API)打成一个 report 包:
- 函数写法示例:
id => {<br> if (id.includes('src/modules/report/')) return 'report';<br> if (id.includes('src/modules/dashboard/')) return 'dashboard';<br> return undefined;<br>} - 这样后续新增该目录下的文件自动归属对应 chunk,无需每次手动维护配置;
- 配合动态导入(
defineAsyncComponent或import())使用效果更佳,天然形成路由级 chunk。
避免碎片化与循环依赖的实操提醒
过度拆分会导致大量小 chunk(如 1–2KB),增加 HTTP 请求压力;盲目合并又易引发循环依赖。几个关键点:
- 函数返回
null或undefined表示不参与 manualChunks,走默认 chunk 分配; - 不要让两个不同 chunk 同时包含同一深层依赖(如 A 和 B chunk 都引用了
lodash/debounce),这容易触发循环或重复打包; - 建议优先用对象写法管理第三方库,用函数写法管理业务代码,职责分离更清晰;
- 构建后检查
dist/assets/目录,确认 chunk 文件名、大小是否符合预期,再结合rollup-plugin-visualizer查看依赖图验证合理性。











