浅谈Webpack4 Tree Shaking 终极优化指南(2)

最后,你需要使用一个支持删除死代码的压缩器。这种压缩器将识别出 Webpack 是如何标记它认为没有被使用的代码,并将其剥离。TerserPlugin 支持这个功能,推荐使用。

下面是 Webpack 开启  tree-shaking 的基本配置:

// Base Webpack Config for Tree Shaking const config = { mode: 'production', optimization: { usedExports: true, minimizer: [ new TerserPlugin({...}) ] } };

有什么副作用

仅仅因为 Webpack 看不到一段正在使用的代码,并不意味着它可以安全地进行 tree-shaking。有些模块导入,只要被引入,就会对应用程序产生重要的影响。一个很好的例子就是全局样式表,或者设置全局配置的JavaScript 文件。

Webpack 认为这样的文件有“副作用”。具有副作用的文件不应该做 tree-shaking,因为这将破坏整个应用程序。Webpack 的设计者清楚地认识到不知道哪些文件有副作用的情况下打包代码的风险,因此默认地将所有代码视为有副作用。这可以保护你免于删除必要的文件,但这意味着 Webpack 的默认行为实际上是不进行 tree-shaking。

幸运的是,我们可以配置我们的项目,告诉 Webpack 它是没有副作用的,可以进行 tree-shaking。

如何告诉 Webpack 你的代码无副作用

package.json 有一个特殊的属性 sideEffects,就是为此而存在的。它有三个可能的值:

true 是默认值,如果不指定其他值的话。这意味着所有的文件都有副作用,也就是没有一个文件可以 tree-shaking。

false 告诉 Webpack 没有文件有副作用,所有文件都可以 tree-shaking。

第三个值 […] 是文件路径数组。它告诉 webpack,除了数组中包含的文件外,你的任何文件都没有副作用。因此,除了指定的文件之外,其他文件都可以安全地进行 tree-shaking。

每个项目都必须将 sideEffects 属性设置为 false 或文件路径数组。在我公司的工作中,我们的基本应用程序和我提到的所有共享库都需要正确配置 sideEffects 标志。

下面是 sideEffects 标志的一些代码示例。尽管有 JavaScript 注释,但这是 JSON 代码:

// 所有文件都有副作用,全都不可 tree-shaking { "sideEffects": true } // 没有文件有副作用,全都可以 tree-shaking { "sideEffects": false } // 只有这些文件有副作用,所有其他文件都可以 tree-shaking,但会保留这些文件 { "sideEffects": [ "./src/file1.js", "./src/file2.js" ] }

全局 CSS 与副作用

首先,让我们在这个上下文中定义全局 CSS。全局 CSS 是直接导入到 JavaScript 文件中的样式表(可以是CSS、SCSS等)。它没有被转换成 CSS 模块或任何类似的东西。基本上,import 语句是这样的:

// 导入全局 CSS import './MyStylesheet.css';

因此,如果你做了上面提到的副作用更改,那么在运行 webpack 构建时,你将立即注意到一个棘手的问题。以上述方式导入的任何样式表现在都将从输出中删除。这是因为这样的导入被 webpack 视为死代码,并被删除。

幸运的是,有一个简单的解决方案可以解决这个问题。Webpack 使用它的模块规则系统来控制各种类型文件的加载。每种文件类型的每个规则都有自己的 sideEffects 标志。这会覆盖之前为匹配规则的文件设置的所有 sideEffects 标志。

所以,为了保留全局 CSS 文件,我们只需要设置这个特殊的 sideEffects 标志为 true,就像这样:

// 全局 CSS 副作用规则相关的 Webpack 配置 const config = { module: { rules: [ { test: /regex/, use: [loaders], sideEffects: true } ] } };

Webpack 的所有模块规则上都有这个属性。处理全局样式表的规则必须用上它,包括但不限于 CSS/SCSS/LESS/等等。

什么是模块,模块为什么重要

现在我们开始进入秘境。表面上看,编译出正确的模块类型似乎是一个简单的步骤,但是正如下面几节将要解释的,这是一个会导致许多复杂问题的领域。这是我花了很长时间才弄明白的部分。

首先,我们需要了解一下模块。多年来,JavaScript 已经发展出了在文件之间以“模块”的形式有效导入/导出代码的能力。有许多不同的 JavaScript 模块标准已经存在了多年,但是为了本文的目的,我们将重点关注两个标准。一个是 “commonjs”,另一个是 “es2015”。下面是它们的代码形式:

// Commonjs const stuff = require('./stuff'); module.exports = stuff; // es2015 import stuff from './stuff'; export default stuff;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/9223838595148c24edd06e3c33baaa41.html