什么是tree-shaking
别名叫摇晃树,最早是由Rollup实现,是一种采用删除不需要的额外代码的方式优化代码体积的技术
tree-shaking会在打包过程中 静态分析 模块之间的导入导出,确定哪些模块导出值没有被使用饼打上标记,并将其删除,从而实现了打包产物的优化。
tree-shaking可以实现的基础
在之前CommonJs、AMD、CMD的模块化方案中,这种导入导出是动态的,难以预测的,因此在打包阶段,是无法分析哪些模块被使用,例如:
if(someTrue){
require('./bar');
exports.foo = 'foo';
}
而ES 静态module方案下,模块之间的依赖关系是高度确定的静态的,与运行状态无关,可以进行可靠的静态分析,因此整个依赖树可以被静态地推导出解析语法树,可以做到在编译时候 分析ESM的模块,可以从代码字面量中推断出哪些模块没有被使用,这就是tree-shaking实现的必要条件。
tree-shaking的作用示例
可以看到示例中,bar.js中导出了bar、foo,而只有bar在index.js中使用过,foo从未被用过,经过tree-shaking处理后,foo变量会被视作无用代码删除。
// index.js
import {bar} from './bar';
console.log(bar);
// bar.js
export const bar = 'bar';
export const foo = 'foo';
需要注意的是,export default 导出的是一个对象,「无法通过静态分析判断出一个对象的哪些变量未被使用,所以 tree-shaking 只对使用 export 导出的变量生效」
tree shaking的原理是什么?
看完上面的分析,相信这里你可以很容易的得出题目的答案了:
- ES6 Module引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
- 静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码
配置
mode = ''production" 会自动启动 tree shaking(webpack4以上会默认开启)
package.json中:
"sideEffects": [
"@babel/polyfill",
"*.css",
"*.less"
],
sideEffects一般用于npm包标记是否有副作用。有副作用则不能去移除,移除了可能会出现bug
例如src目录下有一个extends.js文件
// extends.js
Number.prototype.pad = function(size){
let result = this + ""
while(result.length < size){
result = "0" + result
}
return result;
}
在index.js中执行这个模块的内容,为Number原型对象上添加一个pad方法。再执行一个公共css代码模块。
// index.js
import { Button } from "./components"
import "./extends"
import "./global.css"
console.log((8).pad(3));
document.body.appendChild(Button())
extends.js模块和global.css模块都没被打包,而实际上这里是要打包的,
所以就要package.json中关闭副作用
"sideEffects": [
"./src/extends.js",
"*.css"
]