什么是Tree Shaking
- Tree Shaking 是一个术语,在计算机中表示消除死代码(dead_code);
- 最早的想法起源于LISP,用于消除未调用的代码(纯函数无副作用,可以放心的消除,这也是为什么要求我们在进行函数式编程时,尽量使用纯函数的原因之一);
- 后来Tree Shaking也被应用于其他的语言,比如JavaScript、Dart;
JavaScript的Tree Shaking:
- 对JavaScript进行Tree Shaking是源自打包工具 rollup(后面我们也会讲的构建工具);
- 这是因为Tree Shaking依赖于ES Module的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系);
- webpack2正式内置支持了ES2015模块,和检测未使用模块的能力;
- 在webpack4正式扩展了这个能力,并且通过 package.json 的 sideEffects 属性作为标记,告知webpack在编译时,哪里文件可以安全的删除掉;
- webpack5中,也提供了对部分CommonJS的tree shaking的支持;
webpack中如何实现Tree Shaking(JS)
事实上,webpack实现Tree Shaking采用了两种不同的方案:
- usedExports:通过标记某些函数是否被使用,之后通过Terser来进行优化;
- sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用。
1.usedExports
1)将mode设置为development模式:为了可以看到 usedExports带来的效果,我们需要设置为 development 模式。
因为在 production 模式下,webpack默认的一些优化会带来很大的影响。
2)设置usedExports为true和false对比打包后的代码:
在usedExports设置为true时,会有一段注释:unused harmony export mul;这段注释的意义是什么呢?告知Terser在优化时,可以删除掉这段代码。
这个时候,我们j将minimize设置true:
- usedExports设置为false时,mul函数没有被移除掉;
- usedExports设置为 true 时,mul函数有被移除掉;
所以,usedExports实现Tree Shaking是结合Terser来完成的。
optimization: {
usedExports: true, // production自动设置为true
minimize: true,
minimizer: {
...
}
}
2.sideEffects
sideEffects用于告知webpack compiler哪些模块是有副作用的:
- 副作用的意思是这里面的代码有执行一些特殊的任务,不能仅仅通过export来判断这段代码的意义;
- 副作用的问题,在讲React的纯函数时是有讲过的;
在package.json中设置 sideEffects 的值:
- 如果我们将sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports;
- 如果有一些我们希望保留,可以设置为数组;
比如我们有一个format.js、style.css文件:
- 该文件在导入时没有使用任何的变量来接受;
- 那么打包后的文件,不会保留format.js、style.css相关的任何代码;
- 可以在处理css的loader加入sideEffects: true
3.总结
所以,如何在项目中对JavaScript的代码进行TreeShaking呢(生成环境)?
- 在optimization中配置usedExports为true,来帮助Terser进行优化;
- 在package.json中配置sideEffects,直接对模块进行优化;
几个注意点
我们学到为了利用 tree shaking 的优势, 你必须…
- 使用 ES2015 模块语法(即 import 和 export)。
- 确保没有编译器将您的 ES2015 模块语法转换为 CommonJS 的(顺带一提,这是现在常用的 @babel/preset-env 的默认行为,详细信息请参阅文档)。
- 在项目的 package.json 文件中,添加 “sideEffects“ 属性。
- 使用 mode 为 “production” 的配置项以启用更多优化项,包括压缩代码与 tree shaking。
CSS实现Tree Shaking
上面我们学习的都是关于JavaScript的Tree Shaking,那么CSS是否也可以进行Tree Shaking操作呢?
- CSS的Tree Shaking需要借助于一些其他的插件;
- 在早期的时候,我们会使用PurifyCss插件来完成CSS的tree shaking,但是目前该库已经不再维护了(最新更新也是在4年前了);
- 目前我们可以使用另外一个库来完成CSS的Tree Shaking:PurgeCSS,也是一个帮助我们删除未使用的CSS的工具;
安装PurgeCss的webpack插件:
npm install purgecss-webpack-plugin -D
配置PurgeCss
配置这个插件(生产环境):
- paths:表示要检测哪些目录下的内容需要被分析,这里我们可以使用glob(webpack默认安装了);
- 默认情况下,Purgecss会将我们的html、body标签的样式移除掉,如果我们希望保留,可以添加一个safelist的属性;
purgecss也可以对less文件进行处理(所以它是对打包后的css进行tree shaking操作)。new PurgeCssPlugin({
paths: glob.sync(`${resolveApp("./src")}/**/*`, {nodir: true}),
safelist: function() {
return {
standard: ["body", "html"]
}
}
})