Tree Shaking 原理

1. 面试题

Q: 什么是 Tree Shaking?它的原理是什么?为什么必须使用 ESM (import/export)?

2. 核心解答

Tree Shaking (摇树优化) 是一种消除无用代码 (Dead Code Elimination) 的技术。

(1) 原理

Webpack 从入口文件开始建立依赖图,并在遍历时标记被导出的模块

  1. 静态分析:分析代码中的 importexport 语句,识别出哪些模块被导出了。
  2. 标记:对所有导出的模块打上标记。
  3. 消除:在构建打包阶段 (Minification Phase) 移除未使用的代码。如果一个模块没有被任何其他模块引用,则认为它是无用的。

(2) 必须使用 ESM

CommonJS (require/module.exports) 是动态的,难以进行静态分析。因为 CommonJS 可以在运行时动态加载模块 (require('./' + name) ),Webpack 无法确定到底引用了哪个文件,因此很难做 Tree Shaking。 而 ESM (import/export)静态的,必须位于顶层,不能嵌套在条件语句中。Webpack 可以在编译阶段 (Compile Time) 就确定模块的依赖关系,从而安全地移除无用代码。

(3) SideEffects

有些代码虽然没有导出任何变量,但具有副作用 (比如 polyfill, CSS 文件, 全局样式修改)。如果我们简单的把未引用的模块删了,可能会导致程序崩溃。 解决方案:在 package.json 中配置 "sideEffects": false (表示该包无副作用,可放心移除),或者数组形式列出有副作用的文件 ("sideEffects": ["*.css", "*.polyfill.js"])。这是告诉 Webpack:"虽然没用 export,但我干了坏事 (Side Effect),别删我!"。

3. 面试加分项

Q: Tree Shaking 是 Webpack 做的吗?

其实主要工作是在 UglifyJS / Terser (压缩工具) 中完成的。Webpack 负责标记 (Marking) (通过 unused harmony export 注释),而压缩工具负责删除 (Removal) (识别到标记后移除代码)。

4. 面试回答模板

Tree Shaking 是一种删除无用代码的优化技术。Webpack 会基于 ESM 的 import/export 进行静态分析,构建模块依赖关系并标记未使用的导出,最后由 Terser 等压缩工具在生成产物时将这些代码删除。之所以要求使用 ESM,是因为 ESM 的依赖关系在编译阶段就可以确定,而 CommonJS 可能在运行时动态调用 require,难以进行可靠的静态分析。另外,Tree Shaking 不能误删副作用代码,需要通过 package.jsonsideEffects 声明哪些文件不能被移除。