什么是Tree-Shaking

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 [import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)[export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)
treeshaking.gif

webpack在 mode=development 时,默认是不会开启tree-shaking的。需要在 webpack.config.js 中配置

  1. ...
  2. optimization: {
  3. usedExports: true
  4. }
  5. ...

配置完以前设置之后,再模拟一个实际使用的场景。
首先,先创建一个js文件 utils.js

utils.js

  1. export const add = (a, b) =>{
  2. return a + b
  3. }
  4. export const minus = (a, b) => {
  5. return a - b
  6. }

然后在 main.js 中引入并使用。

main.js

  1. import {add, minus} from './utils'
  2. console.log(add(1,2))
  3. if(false){
  4. // 达不到的代码不会被打包
  5. console.log(minus(4,2))
  6. }

执行 npx webpack 打包后查看打包结果
WX20200921-230404@2x.png
可以看到, utils.js 中两个模块都被引入,但是被使用的只有 add 方法。minus 方法没有没用到,所以在打包的时候被剔除了。
development 环境中为了方便调试,只会把模块的使用状态标识一下,并不会真正的把其他未使用的模块剔除。

上面说到过tree-shaking对 ES Module生效,而对CommonJs不生效,接下来我们做个试验。
首先,我们创建一个js文件 utils2.js
utils2.js

  1. const add2 = (a, b) =>{
  2. return a + b
  3. }
  4. const minus = (a, b) =>{
  5. return a - b
  6. }
  7. module.exports = {
  8. add2,
  9. minus
  10. }

然后在 main.js 中引入并使用。

  1. /***************CommonJs引入************/
  2. const count = require('./utils2')
  3. console.log(count.add2(5,6))

然后执行打包命令,查看结果。
image.png
可以看到,“没有找到静态导出,所以的导出都被使用”
所以证实了上面所说的 tree-shaking依赖于 ES2015 模块系统中的静态结构特性。

Tree-Shaking的副作用

在我们的开发中,不仅仅会有上面使用引入模块的方式,还经常会有下面的引入方式:

  1. import './common.css'
  2. ...
  3. ...

上面的这种引入方式,因为整个文件引入,所以这个文件不管你是否使用都被被打包,为了避免过多的无用模块被打包,所以我们可以在 package.json 中配置 "sideEffects":false 来消除副作用,这样这种引入方式的引入的模块就不会被打包。
但是这样设置以后又会带来其他问题。比如说,在common.css 中我们设置 body 的背景色为蓝色。然后在 production 环境下进行打包,会发现 body 设置的样式并没有生效。
我们可以通过设置sideEffects 的配置项来对这种情况进行修正。
sideEffects可接受一个数组,我么设置为

  1. ...
  2. "sideEffects": ["*.css"]
  3. ...

我们再进行打包,这时候我们设置的样式就生效了。

总结

我们在项目中使用tree-shaking需要注意以下几点。

  • 使用 ES2015 模块语法(即 importexport)。
  • 在项目 package.json 文件中,添加一个 “sideEffects” 入口。