1. 概念
Tree-shaking 中文译为摇晃之后的树,用在 webpack 打包中。其功能是移除 JavaScript 上下文中未引用的代码。比如在项目中引用了一个模块 antd 。但其实只使用到了 Button 组件、Input 组件、Form 组件等。那么 webpack 在打包后会消除掉以上组件之外的其他 antd 组件。从而减小打包体积,以此达到性能优化的目的。
新的 webpack 4 正式版本拓展了这个检测的功能。
2. 原理
Tree-shaking 的消除原理是依赖于 ES6 模块系统中的静态结构特性。即 import 和 export。
ES6 模块的特点:
- 只能作为模块顶层的语句出现。
- import 的模块名只能是字符串常量。
- import binding 是 immutable(不可变的) 的。
在 webpack 中使用 Tree-shaking 的三步:
-
找到未使用的代码
模块必须使用 ES6 的 import 导入 和 export 导出,以此找出未使用的代码。 -
标记无副作用
通过 package.json 的sideEffects
属性来标记为"无副作用",可以安全地删除。也可以在 module.rules 配置选项 中设置 “sideEffects”。
{
"name": "your-project",
"sideEffects": false
}
- 安全删除
引入一个能够删除未引用代码(dead code)的压缩工具(minifier)(例如 UglifyJSPlugin)。 从 webpack 4 开始,也可以通过 “mode” 配置选项轻松切换到压缩输出,只需设置为 “production”。也可以在命令行接口中使用--optimize-minimize
标记来使用 UglifyJSPlugin。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
mode: "production"
};
3. 对比
DCE(dead code elimination)译为消除无用代码。其原理是通过编译器判断某些代码根本不影响输出,所以将其消除掉。
Tree-shaking 是 DCE 的一种实现。两者实现的方法又有些不同。DCE 旨在消除不可能执行的代码。而 Tree-shaking 是消除没有用到的代码。
DCE 消除大法:
- 代码不会被执行。
- 代码执行的结果不会被用到。
- 代码只会影响死变量(只读不写)。
例1:
function a(){
return 10;
let x = 30;
return x;
}
以上 a 函数中 return10 之后不会再执行后面的代码,所以会被消除。
例2:
function b(){
let x = 30;
if(false){
x = 100;
};
return x;
}
以上 b 函数中 if(false) 永远不会满足条件,即该片段也不会执行,所以会被消除。
Tree-shaking 消除大法:
- 只能处理函数和顶层的 import/expor 变量,不能消除没用到的类的方法。
- Javascript 动态语言的特性使得静态分析比较困难。
- 如果静态分析的时候删除某些方法,程序运行时就可能报错,那就本末倒置了。
传统编译型语言中都是由编译器将 dead code 从 AST (抽象语法树)中删除。我们都知道 JavaScript 不是编译型语言,所以一般是由 uglify 插件来完成 Javascript 的 DCE。