ES Module 的静态分析和 Tree Shaking 原理是什么?
请解释 ES Module 为什么能被静态分析,以及 Tree Shaking 是如何移除未使用代码的。
回答
Yahuda
ES Module 的静态分析:
import/export必须位于文件顶层,不能写在条件语句中- 模块的依赖关系在编译阶段(而非运行时)即可确定
- 这种静态结构使得打包工具可以分析出:
- 哪些导出被使用了
- 哪些导出未被使用(dead code)
- 依赖关系的 DAG 图
Tree Shaking 原理(以 Webpack/Rollup 为例):
// math.js
export function add(a, b) { return a + b; }
export function multiply(a, b) { return a * b; }
// main.js
import { add } from './math';
console.log(add(1, 2));
// multiply 被标记为未使用,在构建时会被移除
步骤:
- 模块依赖分析:构建 AST,识别所有 import/export
- 标记:标记每个导出是否被引用
- 副作用分析:判断模块是否有副作用(sideEffects)
- 死代码移除:使用 Terser/UglifyJS 删除未使用的导出代码
条件:
- 必须使用 ES Module 语法(CommonJS 无法静态分析)
- package.json 中配置
"sideEffects": false告知打包工具安全删除 - 生产模式、启用代码压缩
CommonJS 无法 Tree Shaking 的原因:
require可以在条件语句中module.exports可以动态计算(如赋值给变量)- 无法在编译时确定导出成员