三石的webpack(tree-shaking篇)

366 阅读3分钟

概念

tree shaking,也称摇树。
当你引入一个模块时,你可能用到的只是其中的某些功能,这个时候,我们不希望这些无用的代码打包到项目中去。通过tree-shaking,就能删除无用代码,以达到减小体积,缩短 http 请求时间,起到一定效果的页面优化

触发条件

开启 tree-shaking,需要满足以下三个条件:

使用es module的模块规范

tree-shking建立在es module静态分析的基础之上,所以代码必须使用esm的规范。业务代码一般都会使用esm,但是引入的第三方依赖就不一定了。比如lodash就是commonjs规范的,直接使用lodash是不会触发treeshking的,解决方案就是使用lodash的esm版本lodash-es。

package.json中的main字段是node package的入口,但是是commonjs规范的。想要使用treeshking的功能必须使用esm的入口,所以rollup(最早的treeshking实现)提出了module字段的提案,在这里配置es module的入口,这种约定虽然还没有成为规范,但已经被很多包所实现了。比如vue的package.json

如果你在使用Babel,这一点可能已让你遇到麻烦了。因为Babel的预置默认把任何模块转译成CommonJS模块。你可以简单设置modules: false来解决此问题,在.babalrc或者webpack.config.js中设置都可以

开启 optimization.usedExports

optimization.providedExports配置能使 webpack 确定每个模块导出项(exports)的使用情况。然后optimization.usedExports收集到的信息会被其他优化项或产出代码使用到(模块未用到的导出项不会被导出,在语法完全兼容的情况下会把导出名称混淆为单个char)。为了最小化代码体积,未用到的的导出项目(exports)会被删除。

webpack4 默认production模式会开启 optimization.usedExports。

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

所以:

webpack4中,如果一些模块导出了一个对象,用到这个模块的地方只使用了某几个方法,其余的方式是不能被treeshking的。原因也是因为编译期间的静态分析只能对es module的相关语法做分析,是不会真正去执行代码的。

使用压缩插件

webpack4 默认production模式会开启压缩插件

如何控制范围?

我们知道,treeshaking 就是有副作用时(引入但未使用),打包时会删掉这些无效引用。但某些情况下,我们又不能删掉,这就需要我们精准控制了

  1. 通过 package.json 的 "sideEffects" 属性,控制是否有副作用文件
{
  ...
  "sideEffects": false  // 整个项目都没副作用,也就是说,会全部删掉无效引用
}

注意,任何导入的文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并导入 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:

{
  "name": "webpack-demo",
  "sideEffects": [
    "*.css" // *.css文件有副作用,不能直接删掉
  ]
}
  1. 通过注释标记函数为无副作用函数。如果一个没被使用的变量定义的初始值被认为是无副作用的(pure),它会被标记为死代码,不会被执行且会被压缩工具清除掉。
/*#__PURE__*/ double(55);

webpack5 中的tree-shaking

webpack5 以前,tree-shaking 比较简单,主要是找import进来的变量是否在这个模块内出现过,出现过则不剔除,否则剔除,并且用于 esModule 中

webpack5,可以进行根据作用域之间的关系进行优化。如:

a.js 中定义了两个方法 x 和 y,在 index.js 中引入了 a.js 的 x 方法。那么 webpack4 打包出来的结果包含了 index.js 和 a.js 的内容,包含了没有用到的 y 方法。但是 webpack5 的 treeshaking,会进行作用域分析,打包结果只有 index 和 a 文件中的 a 方法,没有用到的 b 方法是不会被打包进来的。

注意:如果引用了但是并未使用, tree-shaking 也会剔除掉

原理

还没了解,先挂着
Tree-Shaking性能优化实践 - 原理篇