Tree Shaking 生效需满足静态可分析性与无副作用:类中实例属性若含函数调用、请求、日志等即触发副作用,导致模块无法被剔除;应将副作用延迟至构造函数、方法或 getter 中执行,并通过 "sideEffects": false 或命名导出函数提升摇树效果。

Tree Shaking 要生效,关键在于让构建工具(如 Webpack、Rollup)能**静态确认某个导出确实未被使用**,且该导出**不带副作用**。而类实例属性本身不会直接触发副作用,但若在定义或赋值过程中执行了函数调用、修改全局状态、发起请求、监听事件等操作,就会被构建工具视为“有副作用”,从而阻止整个模块被摇掉——哪怕你只用了一个方法,其他导出也可能因“可能影响运行时行为”而被迫保留。
确保类定义本身无副作用
类声明(class MyClass { ... })是语法声明,本身无副作用;但若在类体中直接执行代码(比如初始化实例属性时调用函数),就危险了:
❌ 危险写法(引入副作用):
export class ApiClient {
// 构造函数外的赋值语句,会在模块加载时立即执行
baseUrl = fetch('/config').then(r => r.json()); // ❌ 网络请求,强副作用
logger = console.log('ApiClient loaded'); // ❌ 打印日志,副作用
}
这类代码会让整个 ApiClient 模块无法被 Tree Shaking 安全剔除,即使你只 import 了它的某个静态方法。
立即学习“Java免费学习笔记(深入)”;
✅ 安全写法:
- 把副作用逻辑移到构造函数、方法或工厂函数中,延迟到真正使用时才执行
- 实例属性仅做简单赋值(字面量、函数引用、已声明变量)
export class ApiClient {
baseUrl = '/api'; // ✅ 字面量,无副作用
constructor(config) {
this.config = config;
// ✅ 副作用推迟到实例化时,不影响模块导出分析
}
request() {
return fetch(this.baseUrl + '/data'); // ✅ 副作用在方法内,按需执行
}
}
避免在静态属性或类字段中调用函数
ES 提案中的公共类字段(public class fields)若含函数调用,同样会触发副作用:
❌ 不推荐:
export class Utils {
formatter = new Intl.NumberFormat('zh-CN'); // ❌ 实例化对象,有副作用
cache = new Map(); // ❌ 创建新对象,有副作用
}
构建工具无法判断 Map 或 Intl.NumberFormat 的构造是否安全,保守起见会保留整个模块。
✅ 推荐方式:
- 用 getter 延迟初始化(静态分析可识别其非强制执行)
- 或改用静态方法/工厂函数封装创建逻辑
export class Utils {
get formatter() {
return new Intl.NumberFormat('zh-CN'); // ✅ getter 不自动执行,Tree Shaking 可忽略
}
static createCache() {
return new Map(); // ✅ 显式调用才执行,不影响导出分析
}
}
显式标记模块无副作用
如果确认类模块整体没有顶层副作用(即 import 该模块不会改变任何状态、不发请求、不打日志),可在 package.json 中声明:
{
"sideEffects": false
}
或针对具体文件列表:
{
"sideEffects": ["./src/index.js", "*.css"]
}
这样 Webpack 就知道:只要没 import 这个模块的导出,整个文件都可以被安全移除。注意:一旦模块顶层有表达式执行(哪怕只是 console.log),就不能设 "sideEffects": false。
优先使用命名导出 + 函数式设计
相比类,纯函数 + 命名导出更利于 Tree Shaking:
- 函数体内的副作用不影响导出标识的静态分析
- 未被 import 的函数会被完整剔除
- 避免类字段隐式执行带来的不确定性
// utils.js
export function add(a, b) { return a + b; }
export function apiRequest(url) { return fetch(url); } // ✅ 即使内部有副作用,add 仍可被单独摇掉
// main.js
import { add } from './utils.js'; // ✅ 只引入 add,apiRequest 不会进包


















