webpack5的tree-shaking值得了解
什么是 tree shaking?tree shaking 的意思是,webpack 在打包的时候将会剔除掉被没有被使用到的代码达到减小体积,缩短 http 请求时间,起到一定效果的页面优化。webpack4 和webpack5 的 tree shaking 还是存在很大的区别。(不是吧,现在都已经 webpack5 了, webpack4 我都还没用过,哈哈哈。)
那么我们如何使用 tree shaking 呢?这个功能 webpack5 已经自带了,而且默认是开启的功能,让我们来实验一下吧!先初始化项目然后安装依赖。
npm init -y
npm install webpack webpack -D
然后准备下面的代码结构,执行 npx webpack 进行打包输出。
// a.js
export default {
a: 1
}
// index.js
import a from './a'
// 或者 import './a'
// 没有使用a变量
console.log('hello world');
最后发现产出的代码是:把 a 文件里面的所有代码都删除掉了。好厉害!
(()=>{"use strict";console.log("hello world")})();
此时 tree shaking 达到的我们想要的效果,剔除了没有使用的代码。但是 webpack 是怎么知道我们代码没有使用呢?如果是一部分代码使用了,一个代码没有使用,他的规则是怎样处理的呢?我们进行进一步分析。
// a.js
function a () {
console.log('a')
}
function b () {
console.log('b')
}
export default {
a, b
}
// index.js
import a from './a'
// 使用a变量,调用文件里面的a函数,不使用b函数
console.log(a.a())
console.log('hello world');
最后发现产出的代码是:把 a 文件里面的部分代码被删除掉了。删除了没有使用到的 b 函数,正确的保留了 a 函数。注意 webpack4 是做不到这一点的,只有 webpack5 才有这个功能。webpack 4 没有分析模块的导出和引用之间的依赖关系。webpack 5 可以对模块中的标志进行分析,找出导出和引用之间的依赖关系。
(()=>{"use strict";const o=function(){console.log("a")};console.log(o()),console.log("hello world")})();
Webpack 跟踪整个应用程序的 import/export 语句,因此,如果它看到导入的东西最终没有被使用,它会认为那是“死代码”,并会对其进行 tree-shaking 。
死代码并不总是那么明确的。下面是一些死代码和“活”代码的例子,希望能让你更明白。
// 导入并赋值给 JavaScript 对象,然后在下面的代码中被用到
// 这会被看作“活”代码,不会做 tree-shaking
import Stuff from './stuff';
doSomething(Stuff);
// 导入并赋值给 JavaScript 对象,但在接下来的代码里没有用到
// 这就会被当做“死”代码,会被 tree-shaking
import Stuff from './stuff';
doSomething();
// 导入但没有赋值给 JavaScript 对象,也没有在代码里用到
// 这会被当做“死”代码,会被 tree-shaking
import './stuff';
doSomething();
// 导入整个库,但是没有赋值给 JavaScript 对象,也没有在代码里用到
// 非常奇怪,这竟然被当做“活”代码,因为 Webpack 对库的导入和本地代码导入的处理方式不同。
import 'my-lib';
doSomething();
注意 Webpack 不能百分百安全地进行 tree-shaking。有些模块导入,只要被引入,就会对应用程序产生重要的影响。一个很好的例子就是全局样式表,或者设置全局配置的JavaScript 文件。
Webpack 认为这样的文件有“副作用”。具有副作用的文件不应该做 tree-shaking,因为这将破坏整个应用程序。Webpack 的设计者清楚地认识到不知道哪些文件有副作用的情况下打包代码的风险,因此 webpack4 默认地将所有代码视为有副作用。这可以保护你免于删除必要的文件,但这意味着 Webpack 的默认行为实际上是不进行 tree-shaking。值得注意的是 webpack5 默认会进行 tree-shaking。
如何告诉 Webpack 你的代码无副作用,可以通过 package.json 有一个特殊的属性 sideEffects,就是为此而存在的。
它有三个可能的值:
1、true 如果不指定其他值的话。这意味着所有的文件都有副作用,也就是没有一个文件可以 tree-shaking。
2、false 告诉 Webpack 没有文件有副作用,所有文件都可以 tree-shaking。
3、第三个值 […] 是文件路径数组。它告诉 webpack,除了数组中包含的文件外,你的任何文件都没有副作用。因此,除了指定的文件之外,其他文件都可以安全地进行 tree-shaking。
下面是 sideEffects 标志的一些代码示例。尽管有 JavaScript 注释,但这是 JSON 代码:
// 所有文件都有副作用,全都不可 tree-shaking
{
"sideEffects": true
}
// 没有文件有副作用,全都可以 tree-shaking
{
"sideEffects": false
}
// 只有这些文件有副作用,所有其他文件都可以 tree-shaking,但会保留这些文件
{
"sideEffects": [
"./src/file1.js",
"./src/file2.js"
]
}
webpack4 曾经不进行对 CommonJs 导出和 require() 调用时的导出使用分析。webpack 5 增加了对一些 CommonJs 构造的支持,允许消除未使用的 CommonJs 导出,并从 require() 调用中跟踪引用的导出名称。
所以建议大家升级 webpack5,性能也会有很大提升!值得推荐。