# tree-shaking的基本使用
tree-shaking是一个术语,主要用于去除js中未被使用的代码。因为它依赖于es5模块语法的静态结构特性,所以只适用于esmoudle语法,不支持require语法。
下面我们来举例简单说明一下tree-shaking的使用:
src/math.js
export function square(x) {
return x * x;
}
export function sum(a, b) {
return a + b
}
export function cube(x) {
return x * x * x;
}
src/index.js
import { cube } from './math.js'
console.log(cube(5))
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'development',
devtool: false,
optimization: {
usedExports: true,
}
};
我们在终端执行npn rum dev命令后,打开打包后的bundle.js文件,查看输出结果。
下面是简化后的bundle.js文件中的内容
(() => {
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "cube": () => (/* binding */ cube)
/* harmony export */ });
/* unused harmony exports square, sum */
function square(x) {
return x * x;
}
function sum(a, b) {
return a + b
}
function cube(x) {
return x * x * x;
}
})
});
从打包机过来看,我们没有使用到的square和sum函数也被打包进来了,好像我们的tree-shaking没有生效一样,但是如果我们仔细观察,会发现就这样一行代码/* unused harmony exports square, sum */他的作用就是用来标记我们没有使用到的函数的。因为我们上面用的是开发环境,开发环境需要有完整的打包信息,方便我们后续开发调试。
下面我们把webpack配置为生产环境
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'production',
devtool: false,
optimization: {
usedExports: true,
}
};
再次执行打包命令,然后查看打包后的结果:
(()=>{"use strict";console.log(5*5*5)})();去中文就是
由于我们的代码比较简单,webpack对其做了优化,但可以看到我们没有使用square和sum函数已经被去掉了。
所有导入的文件都会受到tree-shaking的影响,如果在项目中使用类似 css-loader 并 import 一个 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除,我们可以在 package.json文件中配置"sideEffects" 属性,来告诉webpack compiler哪些代码是可以安全删除的。
package.json
{
"name": "your-project",
"sideEffects": ["./src/some-side-effectful-file.js", "*.css"]
}
如果我们确保所有的代码都没有副作用我们可以将sideEffects设置为false,告诉webpack可以安全地删除未用到的代码。
综上,使用tree-shaking我们必须做下面:
- 使用 ES2015 模块语法(即 import 和 export)
- 确保没有编译器将您的 ES2015 模块语法转换为 CommonJS 的(顺带一提,这是现在常用的 @babel/preset-env 的默认行为,详细信息请参阅文档)
- 在项目的 package.json 文件中,添加 "sideEffects" 属性
- 使用 mode 为 "production" 的配置项以启用更多优化项,包括压缩代码与 tree shaking。
# tree-shaking的原理
tree-shaking的原理简单总结如下:
- ES6的模块引入是静态分析的,故而可以在编译时正确判断到底加载了什么代码。
- 分析程序流,判断哪些变量未被使用、引用,进而删除此代码。
关于tree-shaking这里推荐两篇非常不错的文章,感兴趣的读者可以看看看你的Tree-Shaking并没什么卵用 (opens new window)和Tree-Shaking性能优化实践 - 原理篇 (opens new window)