Tree Shaking
什么是Tree-Shaking
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。
webpack在 mode=development 时,默认是不会开启tree-shaking的。需要在 webpack.config.js 中配置
...
optimization: {
usedExports: true
}
...
配置完以前设置之后,再模拟一个实际使用的场景。
首先,先创建一个js文件 utils.js
utils.js
export const add = (a, b) =>{
return a + b
}
export const minus = (a, b) => {
return a - b
}
然后在 main.js 中引入并使用。
main.js
import {add, minus} from './utils'
console.log(add(1,2))
if(false){
// 达不到的代码不会被打包
console.log(minus(4,2))
}
执行 npx webpack 打包后查看打包结果
可以看到, utils.js 中两个模块都被引入,但是被使用的只有 add 方法。minus 方法没有没用到,所以在打包的时候被剔除了。
在 development 环境中为了方便调试,只会把模块的使用状态标识一下,并不会真正的把其他未使用的模块剔除。
上面说到过tree-shaking对 ES Module生效,而对CommonJs不生效,接下来我们做个试验。
首先,我们创建一个js文件 utils2.js 。utils2.js
const add2 = (a, b) =>{
return a + b
}
const minus = (a, b) =>{
return a - b
}
module.exports = {
add2,
minus
}
然后在 main.js 中引入并使用。
/***************CommonJs引入************/
const count = require('./utils2')
console.log(count.add2(5,6))
然后执行打包命令,查看结果。
可以看到,“没有找到静态导出,所以的导出都被使用”
所以证实了上面所说的 tree-shaking依赖于 ES2015 模块系统中的静态结构特性。
Tree-Shaking的副作用
在我们的开发中,不仅仅会有上面使用引入模块的方式,还经常会有下面的引入方式:
import './common.css'
...
...
上面的这种引入方式,因为整个文件引入,所以这个文件不管你是否使用都被被打包,为了避免过多的无用模块被打包,所以我们可以在 package.json 中配置 "sideEffects":false 来消除副作用,这样这种引入方式的引入的模块就不会被打包。
但是这样设置以后又会带来其他问题。比如说,在common.css 中我们设置 body 的背景色为蓝色。然后在 production 环境下进行打包,会发现 body 设置的样式并没有生效。
我们可以通过设置sideEffects 的配置项来对这种情况进行修正。sideEffects可接受一个数组,我么设置为
...
"sideEffects": ["*.css"]
...
总结
我们在项目中使用tree-shaking需要注意以下几点。
- 使用 ES2015 模块语法(即
import和export)。 - 在项目
package.json文件中,添加一个 "sideEffects" 入口。