这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战
介绍
经常会在面试或者一些官方资料中听到tree shaking(即摇树)这个词,其实它是webpack2以后为了优化缩小打包体积的一种内置的优化方案。因为1个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到打包文件夹里面去,简而言之,tree shaking就是把真正用的代码进行打包,而没用到的代码则会在uglify阶段被擦除掉。本期我们就了解一下它是如何使用的还有使用时要注意什么。
使用
webpack目前是默认支持的,在.babelrc里设置modules:false即可,还有在mode为production的情况下也默认开启。
为了测试,我们这里先写一个js文件里面写几个函数。
// tools.js
export function toolA(){
return "This is my tool-A"
}
export function toolB(){
return "This is my tools-B"
}
export function toolC(){
return "This is my tools-C"
}
然后我们引入到主逻辑app.js中,toolA不使用,toolB无效使用,toolC正常使用。
// app.js
import { toolA,toolB,toolC } from "../utils/tools"
if(false){
console.log(toolB())
}
console.log(toolC())
然后我们把其mode模式变为none,观察其打包后结果如何。
// webpack.config.js
module.exports = {
mode:"none",
entry: {
"app": path.resolve(__dirname, "src/app.js")
},
// ... more config
}
我们发现如果不使用的时候会把我们不用的代码和无效的代码都打进了包里面。
接下来,我们开启tree shaking,因为刚才说过了它是webpack的内置的功能,所以把mode变为production就可以使用了,然后再来看看结果吧。
// webpack.config.js
module.exports = {
mode:"production",
entry: {
"app": path.resolve(__dirname, "src/app.js")
},
// ... more config
}
此时不使用的toolA和无效使用的toolB都没有打包进去,符合我们的期望,tree shaking使用成功了。
注意
值得注意的是,我们要使用webpack的tree shaking,在webpack5以前的版本其书写的代码语法不能为CommonJS,而必须是ES6的语法才可行。webpack5之后开放支持了CommonJS。
原理
要说webpack tree shaking原理的话,大致会经历babel编译,webpack摇树识别在无效代码上加标识,然后用uglifyjs代码压缩并擦除被标识的无效代码,最后处理兼容后导出这么几个阶段。那么问题来了,我们怎么识别出来哪些有用哪些没用呢?
这里先看一下的DCE原则,DCE(Elimination)是代码不会被执行,不可到达,代码执行的结果不会被用到,代码只会影响死变量(只写不读),通过这些特点去做识别,然后利用ES6模块的特点,如,import只能在模块顶层的语句出现,还有就是import的模块名必须是字符串常量而且binging是immutable的,也就是静态不可修改的。根据这些标识出来,再到uglify阶段去擦除标识也就是这些无用的代码。
结语
因为webpack本身已经集成了tree shaking,所以使用起来极其的简单,甚至很多新来的小伙伴根本没有意识到打包完的代码里面已经做了摇树优化,如果大家有时间也可以看看源码,也是一种学习手段。