Q: 什么是 Tree Shaking?它的原理是什么?为什么必须使用 ESM (import/export)?
Tree Shaking (摇树优化) 是一种消除无用代码 (Dead Code Elimination) 的技术。
Webpack 从入口文件开始建立依赖图,并在遍历时标记被导出的模块。
import 和 export 语句,识别出哪些模块被导出了。CommonJS (require/module.exports) 是动态的,难以进行静态分析。因为 CommonJS 可以在运行时动态加载模块 (require('./' + name) ),Webpack 无法确定到底引用了哪个文件,因此很难做 Tree Shaking。
而 ESM (import/export) 是静态的,必须位于顶层,不能嵌套在条件语句中。Webpack 可以在编译阶段 (Compile Time) 就确定模块的依赖关系,从而安全地移除无用代码。
有些代码虽然没有导出任何变量,但具有副作用 (比如 polyfill, CSS 文件, 全局样式修改)。如果我们简单的把未引用的模块删了,可能会导致程序崩溃。
解决方案:在 package.json 中配置 "sideEffects": false (表示该包无副作用,可放心移除),或者数组形式列出有副作用的文件 ("sideEffects": ["*.css", "*.polyfill.js"])。这是告诉 Webpack:"虽然没用 export,但我干了坏事 (Side Effect),别删我!"。
其实主要工作是在 UglifyJS / Terser (压缩工具) 中完成的。Webpack 负责标记 (Marking) (通过 unused harmony export 注释),而压缩工具负责删除 (Removal) (识别到标记后移除代码)。