为什么Rollup打包后没Tree Shaking掉未引用的代码?
在用Rollup打包项目时,明明某个工具函数没被引用,但打包后的bundle里还是能看到它的代码。我检查过导出方式是ES模块语法,配置文件也设置了treeshaking: true,这是为什么呢?
比如这个utils.js文件:
export function unusedFunc() { console.log('这个函数没被调用'); }
export function usedFunc() { console.log('这个被用了'); }
在入口文件只引入了usedFunc:
import { usedFunc } from './utils.js';
usedFunc();
打包后的bundle.js里却同时包含两个函数。rollup.config.js的配置是这样的:
export default {
input: 'src/index.js',
output: { format: 'esm' },
treeshake: true
};
试过用@rollup/plugin-commonjs和@rollup/plugin-node-resolve也没改善,是不是需要其他配置?
第一种可能是你的
unusedFunc函数虽然没有被直接调用,但 Rollup 认为它可能会有副作用。JS 里面,函数如果只是定义而没有被调用,Rollup 默认会认为它可能是有副作用的代码,因此不敢轻易移除。你可以通过配置treeshake.moduleSideEffects来告诉 Rollup 哪些模块是没有副作用的。比如把utils.js标记为无副作用:第二种可能是你的项目里用了某些插件或者 Babel 转译工具,导致代码结构发生了变化,Rollup 没法正确分析。比如 Babel 如果把 ES 模块转成了 CommonJS,那就彻底没法 Tree Shaking 了。你提到用了
@rollup/plugin-commonjs和@rollup/plugin-node-resolve,建议检查一下 Babel 配置,确保没有把模块语法转成 CommonJS。还有一种情况是,如果你在
utils.js里写了某些 Rollup 无法确定是否无副作用的代码,比如直接执行了某些顶层逻辑,那也会导致整个模块被保留。举个例子:解决方法是尽量避免在模块顶层写这种可能会被当作副作用的代码。
最后再补充一句,Tree Shaking 是基于静态分析的,所以动态导入、条件语句里引用的代码可能会让 Rollup 无法正确判断。如果你确认代码没问题,可以尝试升级 Rollup 到最新版本,有时候是工具本身的 bug。
总结一下,检查以下几点:
1. 确保模块没有副作用,可以通过
treeshake.moduleSideEffects配置。2. 确保 Babel 或其他工具没有破坏 ES 模块结构。
3. 避免在模块顶层写可能会被认为是副作用的代码。
4. 升级 Rollup 到最新版本。
按照这些步骤调整,应该就能解决你的问题了。
首先,
treeshake: true这个其实是默认值,写了和没写一样。但问题不在这里。Rollup的tree shaking是基于“副作用”判断的,如果你的模块被标记为有副作用,或者它猜不透你的代码会不会影响全局,那就宁可留着也不删。你那个
unusedFunc看起来是纯函数,但Rollup会看整个模块有没有可能产生副作用。比如你试试在utils.js顶部加个这样的注释:不行。关键是你得让Rollup知道这个模块本身没有副作用。改配置:
更关键的是,你在
package.json里加上:这样Rollup才会大胆地把没引用的函数干掉。如果你某个文件是有副作用的(比如自动注册、打log),再单独列出来。
另外,确保你导出的是静态的
export function,别用动态导出或者赋值给对象那种写法,不然tree shaking直接歇菜。WP里面我们处理插件bundle的时候老碰这种问题,最后发现都是
sideEffects没设对,或者commonjs插件把模块转花了。你先把sideEffects: false加上试试,八成就正常了。