什么是tree shaking
tree shaking顾名思义,是摇动一棵树,使树上的枯叶落下。在程序中,其作用就是移除程序中未使用的代码。
举例:
// index.js
import { a } from ‘./‘utils.js; // 导入整个utils.js,但只使用了a方法
// utils.js
export function a() {
// …
}
export function b() {
// …
}
tree shaking的作用就是在打包时删除掉b方法
能够被tree shaking的条件
- 能够被静态分析
- ESM: 因为目前已知模块定义中只有ESM为声明,其他AMD、CJS模块都为表达式,无法被静态分析
- 非表达式生成的export:表达式依赖运行时,因此webpack无法确定其中是否包含副作用,为了安全考虑不会将其删除
- 未使用代码
- 无副作用代码:对于有副作用代码,比如修改了原型链的代码,可能会在项目中其他地方被继承,不能删除
// index.js
import { Button } from ‘./‘utils.js;
// utils.js
function Button(_ref) {}
function withAppProvider() {
// …
}
const Button1 = withAppProvider(Button);
export {
Button,
Button1,
};
其中,Button1是要调用withAppProvider函数返回的结果,在运行时才知道调用withAppProvider的过程是否产生了副作用。
对于这种依赖运行时的方法,因为webpack无法判断是否存在副作用,为了安全,所以不会将其删除.
但是开发者知道这段代码是否有副作用,可以通过sideEffects手动标记告诉webpack需要保留副作用的模块,webpack就可以放心地删除剩余模块未使用的代码。
项目中如何配置
在生产环境开启mode: production
开启mode: production时默认启用了TerserPlugin,就默认开启了tree shaking
注意:babel需要升级到babel7以上,旧版babel会编译成非ESM模块,而babel-loader先执行webpack后打包,这就导致webpack对代码无法进行tree shaking了,新版babel通过将代码输出为ESM形式解决了这个问题
配置sideEffects
- css文件
- 包含全局变量的文件
- 其他包含所需副作用的文件
组件库
webpack打包输出模块为IIFE, 如果组件库如果通过webpack打包成非ESM的,再被第三方引入,那么这个组件库无法在第三方项目中打包时无法被tree shaking
解决办法
- 单独导出:像lodash就是将每个方法都单独打包成一个文件,然后按需引入,但无法一次性引入多个方法
- 使用rollup打包成ESM