tree shaking 生效的关键是模块无副作用,即顶层代码不能执行可观察的外部行为(如修改全局变量、操作 dom、打印日志等);应将副作用封装进函数内延迟执行,并通过 package.json 的 sideeffects 字段精准声明有副作用的文件。

Tree Shaking 要生效,关键前提是模块不能有副作用。全局变量的赋值、修改或声明(如 window.xxx = ...、globalThis.xxx = ...、直接挂载到 document 或 localStorage)都属于典型副作用,会导致整个模块无法被安全剔除,哪怕只用了一个函数。
明确副作用的边界在哪里
副作用不是“用了全局变量”就一定存在,而是指在模块顶层(即 import/export 之外)执行了可观察的外部行为。例如:
-
console.log('init')—— 有副作用(输出日志) -
window.myLib = { version: '1.0' }—— 有副作用(污染全局) -
document.body.classList.add('loaded')—— 有副作用(操作 DOM) -
export const PI = 3.14159—— 无副作用(纯声明导出) -
export function sum(a, b) { return a + b }—— 无副作用(纯函数)
把副作用移到调用时,而不是模块加载时
把原本写在模块顶层的副作用逻辑,封装进函数或类方法中,让使用者显式触发。这样 Tree Shaking 就能安全剔除未被调用的副作用代码。
❌ 错误写法(模块一加载就执行):
// utils.js
console.log('utils loaded'); // 副作用
window.utilsReady = true; // 副作用
export function add(a, b) { return a + b; }
export function init() { /* ... */ } // 即使没调用,模块也无法被摇掉
✅ 正确写法(副作用延迟到函数执行):
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
// utils.js
export function add(a, b) { return a + b; }
export function init() {
console.log('utils loaded');
window.utilsReady = true;
}
此时若项目中只 import 了 add,init 及其内部副作用就不会被打包进来。
用 sideEffects 字段精准标记副作用文件
如果工具库中某些文件确实需要副作用(比如 polyfill、样式注入、全局事件监听),不要把 "sideEffects": false 粗暴设在整个库上,而是:
- 在
package.json中设"sideEffects": ["*.css", "src/init.js"],只列出真正有副作用的路径 - 其余纯工具函数文件(如
src/math.js、src/string.js)默认被视为无副作用 - 确保这些副作用文件本身不导出任何供业务使用的函数,只做初始化工作
避免隐式副作用:ESM 动态特性也要小心
以下写法看似“只是声明”,实则可能触发副作用:
-
export const now = Date.now()—— 每次模块加载都执行,有副作用 -
export default new SomeClass()—— 构造实例是副作用 -
export * from './legacy-bundle.js'—— 若该文件含副作用,会传导过来
推荐改为惰性计算或函数封装:
export const getNow = () => Date.now(); export const createInstance = () => new SomeClass();
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










