定义
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块语法的 静态结构 特性,例如 import 和 export。这个术语和概念实际上是由 ES2015 模块打包工具 rollup 普及起来的。
webpack 2 正式版本内置支持 ES2015 模块(也叫做 harmony modules)和未使用模块检测能力。新的 webpack 4 正式版本扩展了此检测能力,通过 package.json 的 “sideEffects” 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 “pure(纯正 ES2015 模块)”,由此可以安全地删除文件中未使用的部分。
将文件标记为 side-effect-free(无副作用)
在一个纯粹的 ESM 模块世界中,很容易识别出哪些文件有副作用。然而,我们的项目无法达到这种纯度,所以,此时有必要提示 webpack compiler 哪些代码是“纯粹部分”。
“side effect(副作用)” 的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
通过 package.json 的 “sideEffects” 属性,来实现这种方式。
{"name": "project-name","sideEffects": false //
}
sideEffects取值:
false
如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack 它可以安全地删除未用到的 export;
数组
如果你的代码确实有一些副作用,可以改为提供一个数组
{"name": "your-project","sideEffects": ["./src/some-side-effectful-file.js"]
}
此数组支持简单的 glob 模式匹配相关文件。其内部使用了 glob-to-regexp(支持:*,**,{a,b},[a-z])。如果匹配模式为 .css,且不包含 /,将被视为 **/.css
Tip
注意,所有导入文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并 import 一个 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:
{"name": "your-project","sideEffects": ["./src/some-side-effectful-file.js", "*.css"]
}
解释 tree shaking 和 sideEffects
sideEffects 和 usedExports(更多被认为是 tree shaking)是两种不同的优化方式。
sideEffects 更为有效 是因为它允许跳过整个模块/文件和整个文件子树。
usedExports 依赖于 terser 去检测语句中的副作用。它是一个 JavaScript 任务而且没有像 sideEffects 一样简单直接。而且它不能跳转子树/依赖由于细则中说副作用需要被评估。尽管导出函数能运作如常,但 React 框架的高阶函数(HOC)在这种情况下是会出问题的。
将函数调用标记为无副作用
.
是可以告诉 webpack 一个函数调用是无副作用的,只要通过 /#PURE/ 注释。它可以被放到函数调用之前,用来标记它们是无副作用的(pure)。传到函数中的入参是无法被刚才的注释所标记,需要单独每一个标记才可以。如果一个没被使用的变量定义的初始值被认为是无副作用的(pure),它会被标记为死代码,不会被执行且会被压缩工具清除掉。这个行为被会开启当 optimization.innerGraph 被设置成 true。
// file.js
/*#__PURE__*/ double(55);
压缩输出结果
通过 import 和 export 语法,我们已经找出需要删除的“未引用代码(dead code)”,然而,不仅仅是要找出,还要在 bundle 中删除它们。为此,我们需要将 mode 配置选项设置为 production。
结论
为了利用tree-shaking的优势,我们需要:
- 使用ES2015模块语法;
- 确保没有编译器将您的 ES2015 模块语法转换为 CommonJS 的(顺带一提,这是现在常用的 @babel/preset-env 的默认行为,详细信息请参阅文档);
- 在项目的 package.json 文件中,添加 “sideEffects” 属性;
- 使用 mode 为 “production” 的配置项以启用更多优化项,包括压缩代码与 tree shaking;
参考文献
- tree-shaking