为什么我的Tree Shaking没生效?providedExports配置有问题吗?
我在项目里用rollup打包时遇到了奇怪的问题。明明只导入了utils.js里的add函数,但打包结果里却包含了整个math模块:
// utils.js
import { add } from './math'; // math.js里还有subtract/multiply等函数
export function sum(a, b) {
return add(a, b);
}
检查rollup配置时发现,虽然设置了”exports”: “auto”,但生成的package.json里providedExports还是空的。难道导出路径写错了?还是需要额外配置?
试过手动指定providedExports:”./math”: [“add”],但报错说找不到对应模块。是不是路径匹配有问题?或者Tree Shaking在这里失效的其他原因?
providedExports是给外部依赖用的,不是让你手动指定内部模块的。你手动加./math肯定会报错,因为 Rollup 会去 node_modules 找对应模块。Rollup 的 Tree Shaking 是基于 ES Module 的静态导入导出分析的,有几个关键点:
1. 你的
utils.js导出了sum函数,而sum又调用了add,Rollup 会自动保留add和整个math.js模块。2. **Tree Shaking 并不会自动排除未使用的模块导出**。比如
math.js中的subtract和multiply,如果没在任何地方使用,Rollup 应该能排除掉。但如果整个math.js都被打包进去了,可能是因为它里面有副作用(比如直接执行了某些代码),或者你的构建流程中某些插件“激活”了整个模块。3. 确保你用了
terser或者@rollup/plugin-terser,因为真正的 Dead Code Elimination 是在压缩阶段完成的。4.
exports: 'auto'是正确的配置,providedExports不是你应该操心的字段,它用于外部依赖(比如 peerDependencies)防止被打包进来。优化一下你的配置试试:
然后再看打包结果。如果 math.js 依然整个被打包进来,检查 math.js 是否有副作用或动态导入行为,比如:
去掉副作用代码后,再重新打包试试。如果还是一样,可以贴一下 math.js 内容我帮你分析。
一句话总结:Tree Shaking 依赖静态导入和无副作用模块,
providedExports不是你应该手动干预的字段。首先看你的math.js导出方式:
如果使用默认导出或者混合导出,会导致rollup无法正确分析依赖。这里应该改成命名导出。
然后检查你的rollup配置,需要添加这两个关键配置:
关于providedExports为空的问题,这其实是rollup的特性不是bug。需要满足:
1. 必须是外部依赖(external)
2. 需要配置output.exports为"auto"或"named"
3. 模块必须有具名导出
你手动指定providedExports时报错,大概率是路径问题。正确的写法应该是:
但实际项目中不建议手动配置providedExports,建议改用外部化处理:
需要注意的是:如果math.js是本地文件而不是npm包,这种treeshaking不会生效。因为rollup只对npm包做treeshaking。要优化本地文件的treeshaking,需要整个项目都改用ESM格式+按需导出。
总结处理步骤:
1. 确认math.js使用命名导出
2. 在rollup.config.js中添加nodeResolve和commonjs插件
3. 配置treeshake选项为严格模式
4. 把math.js标记为external
5. 输出格式必须使用esm
如果打包后math.js依然完整保留,建议检查构建产物里的模块id是否和external配置匹配。可以用以下命令调试:
看日志输出的模块id路径是否和你在external函数里写的匹配。这个是最容易出错的地方,有时候路径会带../或者绝对路径,需要根据实际调整。