# 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)