为什么Rollup打包后没Tree Shaking掉未引用的代码?

Good“若溪 阅读 20

在用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也没改善,是不是需要其他配置?

我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
极客缤泽
这个问题其实挺常见的,Rollup 的 Tree Shaking 机制依赖于静态分析,所以有几个可能的原因会导致未引用的代码没被移除。

第一种可能是你的 unusedFunc 函数虽然没有被直接调用,但 Rollup 认为它可能会有副作用。JS 里面,函数如果只是定义而没有被调用,Rollup 默认会认为它可能是有副作用的代码,因此不敢轻易移除。你可以通过配置 treeshake.moduleSideEffects 来告诉 Rollup 哪些模块是没有副作用的。比如把 utils.js 标记为无副作用:

export default {
input: 'src/index.js',
output: { format: 'esm' },
treeshake: {
moduleSideEffects: false
}
};


第二种可能是你的项目里用了某些插件或者 Babel 转译工具,导致代码结构发生了变化,Rollup 没法正确分析。比如 Babel 如果把 ES 模块转成了 CommonJS,那就彻底没法 Tree Shaking 了。你提到用了 @rollup/plugin-commonjs@rollup/plugin-node-resolve,建议检查一下 Babel 配置,确保没有把模块语法转成 CommonJS。

还有一种情况是,如果你在 utils.js 里写了某些 Rollup 无法确定是否无副作用的代码,比如直接执行了某些顶层逻辑,那也会导致整个模块被保留。举个例子:

// utils.js
console.log('这段代码会让 Rollup 认为模块有副作用');
export function unusedFunc() { console.log('这个函数没被调用'); }
export function usedFunc() { console.log('这个被用了'); }


解决方法是尽量避免在模块顶层写这种可能会被当作副作用的代码。

最后再补充一句,Tree Shaking 是基于静态分析的,所以动态导入、条件语句里引用的代码可能会让 Rollup 无法正确判断。如果你确认代码没问题,可以尝试升级 Rollup 到最新版本,有时候是工具本身的 bug。

总结一下,检查以下几点:
1. 确保模块没有副作用,可以通过 treeshake.moduleSideEffects 配置。
2. 确保 Babel 或其他工具没有破坏 ES 模块结构。
3. 避免在模块顶层写可能会被认为是副作用的代码。
4. 升级 Rollup 到最新版本。

按照这些步骤调整,应该就能解决你的问题了。
点赞 3
2026-02-17 23:04
程序猿振艳
你这情况我之前也遇到过,不是Rollup的tree shaking没生效,而是你代码里有些写法会让它“不敢”删代码。

首先,treeshake: true 这个其实是默认值,写了和没写一样。但问题不在这里。Rollup的tree shaking是基于“副作用”判断的,如果你的模块被标记为有副作用,或者它猜不透你的代码会不会影响全局,那就宁可留着也不删。

你那个 unusedFunc 看起来是纯函数,但Rollup会看整个模块有没有可能产生副作用。比如你试试在 utils.js 顶部加个这样的注释:

export const __PURE__ = true;

export function unusedFunc() { console.log('这个函数没被调用'); }
export function usedFunc() { console.log('这个被用了'); }


不行。关键是你得让Rollup知道这个模块本身没有副作用。改配置:

export default {
input: 'src/index.js',
output: { format: 'esm' },
treeshake: {
moduleSideEffects: false // 明确告诉rollup去分析模块副作用
}
}


更关键的是,你在 package.json 里加上:

{
"sideEffects": false
}


这样Rollup才会大胆地把没引用的函数干掉。如果你某个文件是有副作用的(比如自动注册、打log),再单独列出来。

另外,确保你导出的是静态的 export function,别用动态导出或者赋值给对象那种写法,不然tree shaking直接歇菜。

WP里面我们处理插件bundle的时候老碰这种问题,最后发现都是 sideEffects 没设对,或者commonjs插件把模块转花了。你先把 sideEffects: false 加上试试,八成就正常了。
点赞 5
2026-02-10 15:04