简单的tree shaking

605 阅读2分钟

什么是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的条件

  1. 能够被静态分析
    1. ESM: 因为目前已知模块定义中只有ESM为声明,其他AMD、CJS模块都为表达式,无法被静态分析
    2. 非表达式生成的export:表达式依赖运行时,因此webpack无法确定其中是否包含副作用,为了安全考虑不会将其删除
  2. 未使用代码
  3. 无副作用代码:对于有副作用代码,比如修改了原型链的代码,可能会在项目中其他地方被继承,不能删除

// 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

  1. css文件
  2. 包含全局变量的文件
  3. 其他包含所需副作用的文件

组件库

webpack打包输出模块为IIFE, 如果组件库如果通过webpack打包成非ESM的,再被第三方引入,那么这个组件库无法在第三方项目中打包时无法被tree shaking

解决办法

  1. 单独导出:像lodash就是将每个方法都单独打包成一个文件,然后按需引入,但无法一次性引入多个方法
  2. 使用rollup打包成ESM