4-1 Tree Shaking 概念详解

1. 简介

tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 importexport。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup。

新的 webpack 4 正式版本,扩展了这个检测能力,通过 package.json"sideEffects" 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 "pure(纯的 ES2015 模块)",由此可以安全地删除文件中未使用的部分。

2. 使用场景

我们看如下使用场景,主模块 index.js 中引用了一个辅助模块 math.js 中的一个方法。

// index.js

import { add } from './math';

add(1, 2);
// math.js

export const add = (a, b) => {
    console.log(a + b);
};

export const minus = (a, b) => {
    console.log(a - b);
};

打包后如下:


image.png

4-1 Tree Shaking 概念详解_第1张图片
image.png

可以看到,虽然 minus 方法未被使用,但是确被打包在最终的 index.js 文件中,增大了包体。

3. 使用 tree-shaking 摇晃掉多余的代码

现在我们尝试利用 tree shaking 方法来摇晃掉未被使用的代码。
首先,我们要找出未被使用的模块:

module.exports = {
  //...
  optimization: {
    usedExports: true
  }
};

打包后如下


4-1 Tree Shaking 概念详解_第2张图片
image.png

4-1 Tree Shaking 概念详解_第3张图片
image.png

可以看到此时输出代码中仍然有 minus 方法,但是该方法已经被标记为未使用。那么如何在最终代码中删除掉该方法了,需要使用如下插件:

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
...
    plugins: [
        new UglifyJsPlugin(),
        new HtmlWebpackPlugin({
            template: "./src/index.html"
        }),
        new CleanWebpackPlugin()
    ],

打包后如下:


image.png

image.png

可以看到 minus 方法被抖掉了。

3. 将文件标记为无副作用

在一个纯粹的 ESM 模块世界中,识别出哪些文件有副作用很简单。然而,我们的项目无法达到这种纯度,所以,此时有必要向 webpack 的 compiler 提供提示哪些代码是“纯粹部分”。

这种方式是通过 package.json 的 "sideEffects" 属性来实现的。

{
  "sideEffects": false
}

如同上面提到的,如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack,它可以安全地删除未用到的 export 导出。
「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
注意,任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:

{
  "name": "your-project",
  "sideEffects": [
    "./src/some-side-effectful-file.js",
    "*.css"
  ]
}

4. 使用 production 模式

上述其实是描述如何在 development 模式下开启 tree-shaking,但其实在 development 模式下,为了开发和调试方便,我们是不会开启压缩的,而 production 下,会自动为我们开启 tree-shaking。去掉 usedExports 和 uglifyjs-webpack-plugin 相关配置,将 mode 修改为 production:

mode: 'production',

另外,注意文章开头所说的,tree-shaking 依赖于 ES2015 模块系统中的静态结构特性,例如 importexport。所以只有 es-module 才可以被 tree-shaking。

参考

webpack-tree-shaking
https://webpack.js.org/configuration/optimization/#optimizationusedexports
https://segmentfault.com/a/1190000016767989?utm_source=tag-newest

你可能感兴趣的:(4-1 Tree Shaking 概念详解)