Webpack Tree Shaking原理与sideEffects
解释Webpack Tree Shaking(摇树优化)的原理、必要条件,以及package.json中sideEffects字段的作用。为什么Tree Shaking对CommonJS模块无效?如何正确配置以实现最大优化效果?
回答
编译有声
Tree Shaking原理
Tree Shaking依赖ES Module静态分析能力——import/export在编译时确定,而非运行时。
工作流程:
- 标记阶段(Webpack标记未使用导出):
- Webpack遍历模块的AST,标记每个export是否被其他模块引用
- 未被引用的export标记为
/* unused harmony export */
- 移除阶段(TerserWebpackPlugin执行):
- UglifyJS/Terser根据标记删除未使用的代码
- 副作用安全的代码才可安全删除
必要条件:
// ❌ 破坏摇树的写法
import _ from 'lodash'; // 全量导入
require('module'); // CommonJS动态导入
import * as utils from 'utils'; // 命名空间导入
// ✅ 支持摇树的写法
import { debounce } from 'lodash-es'; // 具名导入
import isArray from 'lodash/isArray'; // 路径导入
sideEffects字段
{
"sideEffects": false, // 所有模块无副作用,可安全树摇
"sideEffects": [ // 指定有副作用的模块
"**/*.css",
"./src/polyfill.js"
]
}
- false:告知Webpack所有模块无副作用,未使用的export可安全删除
- 数组:指定的文件有副作用(如CSS、polyfill),不会被移除
- 不设置:所有模块默认被认为有副作用,Tree Shaking效果有限
为什么CommonJS无效?
const module = require('module');
require()是动态的,可以在条件语句中执行module.exports可以随时修改- Webpack无法在编译时确定哪个属性被使用
- 只能全量引入
最佳实践:
- 业务代码:配置
sideEffects: false或具体列表 - 库代码:导出ES Module格式(package.json加
"module":"dist/index.esm.js") - lodash使用
lodash-es代替lodash - 使用babel时配置
"modules": false避免转译import/export - 启用
optimization.usedExports: true和optimization.sideEffects: true