Tree Shaking 失效主因是全局变量副作用,如挂载属性、修改原型、未标注第三方调用等导致模块被判定为非纯;需通过 /#__PURE__/ 标注、隔离副作用、精确配置 sideEffects 字段等方式解决。

Tree Shaking 失效常因全局变量副作用导致——即模块导出虽未被引用,但其初始化逻辑(如赋值、函数调用)被引擎视为“可能影响外部”,从而被迫保留。JavaScript 本身无运行时反射机制判断副作用,打包工具(如 Webpack、Rollup)依赖静态分析和显式提示来安全剔除代码。排查核心是:确认哪些语句被误判为有副作用,再通过代码改造或配置引导工具忽略它们。
识别潜在的副作用语句
以下写法极易触发“非纯模块”判定,导致整个模块无法被 shake:
-
向全局对象挂载属性:如
window.utils = {...}、global.MyLib = class{},即使只在模块顶层执行一次,也被视为对外部环境产生不可逆影响; -
直接修改内置原型:如
Array.prototype.mapAsync = ...,属于典型的全局副作用,且无法被静态分析证明“无影响”; -
调用无标注的第三方函数:如
someThirdParty.init(),若该函数未标注/*#__PURE__*/,工具默认认为它有副作用; -
带副作用的导出赋值:如
export const VERSION = '1.0.0'; export const API = createApi();,后者createApi()若含内部状态或 DOM 操作,会使整个导出块“污染”模块纯净性。
用 /*#__PURE__*/ 显式标记无副作用调用
这是最直接的干预方式。对确定不产生外部影响的函数调用加注释,告诉打包工具可安全移除:
- 正确示例:
/*#__PURE__*/ createConfig({ debug: false })—— 若createConfig只返回普通对象且无闭包副作用; - 错误用法:
/*#__PURE__*/ initAnalytics()—— 若该函数实际发送网络请求或监听事件,加注释反而导致关键逻辑被误删; - 注意:Webpack 5+ 和 Rollup 均支持该语法,但仅作用于紧邻的函数调用,不能跨行或修饰变量声明。
隔离副作用到独立模块或条件分支中
将有副作用的逻辑从默认导出路径中抽离,避免“污染”主模块的纯净性:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 把挂载逻辑移到单独的
entry.js或polyfill.js中,主库只暴露纯函数/类; - 用
if (false)包裹副作用代码(开发时设为 true),现代打包器会识别死代码并剔除,但需确保未启用sideEffects: false全局配置覆盖; - 导出一个“懒初始化”的工厂函数,如
export const createInstance = () => { /* 副作用在此 */ return instance; },调用前不会触发执行。
检查并配置打包工具的 sideEffects 字段
在 package.json 中明确声明模块是否含副作用,是 Tree Shaking 的关键开关:
-
"sideEffects": false表示所有文件都无副作用,工具可安全删除未引用的导出; -
"sideEffects": ["*.css", "src/polyfill.js"]表示仅这些文件有副作用,其余 JS 文件按纯模块处理; - 常见陷阱:将整个
src/**/*写进 sideEffects 列表,等于关闭 Tree Shaking;应尽量缩小范围,或改用false+ 精确标注。
不复杂但容易忽略:副作用不是“功能上有用”,而是“执行时改变外部状态”。只要模块顶层语句不读写全局、不操作 DOM、不发请求、不监听事件,它就是纯的。从这个角度反推每一行代码,比盲目加 /*#__PURE__*/ 更可靠。

















