tree shaking 能否生效取决于模块是否被判定为无副作用。副作用指模块执行时产生的外部可观测影响,如调用 console.log、修改全局对象、操作 dom 等;写出无副作用模块需将所有动作封装进函数,顶层仅声明和导出,并通过 package.json 的 sideeffects 字段或 /#__pure__/ 注释辅助标识。

Tree Shaking 能否生效,关键不在于你写了多少代码,而在于这些代码是否被工具判定为“可安全删除”。只要模块存在副作用,打包工具就会整块保留——哪怕你只用了一个函数。避免副作用不是为了写得更“干净”,而是为了让静态分析能真正起作用。
什么是副作用?哪些行为会触发它
副作用指模块在执行时,除了导出值之外还产生了外部可观测的影响。常见情况包括:
- 直接调用
console.log、alert、fetch等有外部影响的函数 - 修改全局对象(如
window.xxx = ...、Object.prototype.xxx = ...) - 操作 DOM(如
document.body.appendChild(...)) - 给全局变量赋值或读取未声明变量(触发隐式全局)
- 执行带状态变更的初始化逻辑(如注册事件监听器、启动定时器)
怎么写出无副作用的模块
核心原则:模块顶层只做两件事——声明和导出,不做任何“动作”。所有实际执行逻辑都封装进函数里,等被调用时才运行。
- 把初始化代码移到函数内部,例如:
export const initApp = () => { console.log('start'); },而不是在文件顶部直接console.log('start') - 避免在模块顶层访问或修改全局状态,比如不要直接写
localStorage.getItem(...) - 导出纯函数(输入确定、输出确定、无外部依赖),如
export const sum = (a, b) => a + b - 如果必须执行副作用(比如加载 polyfill),单独拆成一个文件,并在
package.json的sideEffects字段中明确列出
如何声明模块无副作用
仅写无副作用代码还不够,你还得告诉打包工具:“这个模块确实可以放心摇”。方式有两种:
- 在
package.json中设置"sideEffects": false,表示整个库无副作用(适合纯工具库) - 若只有部分文件有副作用,改用数组形式:
"sideEffects": ["./src/polyfills.js", "./styles/index.css"] - 对单个模块临时标注(Rollup 支持):
/*#__NO_SIDE_EFFECTS__*/ export const add = (a, b) => a + b;,注释必须紧贴文件开头
别指望注释绕过根本问题
像 /*#__PURE__*/ 这类注释只能帮压缩器删掉某些无副作用的调用,但它不能让一个本身就有副作用的模块变得可摇。如果模块顶层已经执行了 fetch 或修改了 window,加再多注释也没用——Tree Shaking 在标记阶段就放弃了这个模块。
真正有效的做法是:先重构代码,剥离副作用;再通过配置和结构确保工具能识别;最后才考虑用注释微调压缩结果。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











