在 Webpack 中,启动 Tree Shaking 功能必须同时满足三个条件:
1、使用 ESM 规范编写模块代码
2、配置 optimization.usedExports 为 true,启动标记功能
3、启动代码优化功能,可以通过如下方式实现:
- 配置 mode = production
- 配置 optimization.minimize = true
- 提供 optimization.minimizer 数组
module.exports = {
mode: "production",
entry: "./src/index.js",
output: {
filename: 'buildle.js'
},
cache: false,
optimization: {
usedExports: true,// 是否启用标记
minimize: false, // 是否压缩
}
};
依赖收集过程
1、将模块的所有 ESM 导出语句转换为 Dependency 对象,并记录到 module 对象的 dependencies 集合,转换规则:
- 具名导出转换为 HarmonyExportSpecifierDependency 对象
- default 导出转换为 HarmonyExportExpressionDependency 对象
FlagDependencyExportsPlugin.js
编辑切换为居中
添加图片注释,不超过 140 字(可选)
2、所有模块都编译完毕后,触发 compilation.hooks.finishModules 钩子,开始执行FlagDependencyExportsPlugin 插件回调
3、FlagDependencyExportsPlugin 插件从 entry 开始读取 ModuleGraph 中存储的模块信息,遍历所有 module 对象
4、遍历 module 对象的 dependencies 数组,找到所有 HarmonyImportXXXDependency 类型的依赖对象,将其转换为 ExportInfo 对象并记录到 ModuleGraph 体系中
经过 FlagDependencyExportsPlugin 插件处理后,所有 ESM 风格的 export 语句都会记录在 ModuleGraph 体系内,后续操作就可以从 ModuleGraph 中直接读取出模块的导出值
标记过程
1、触发 compilation.hooks.optimizeDependencies 钩子,开始执行 FlagDependencyUsagePlugin 插件逻辑
FlagDependencyUsagePlugin.js
- 触发 compilation.hooks.optimizeDependencies 钩子,开始执行 FlagDependencyUsagePlugin 插件逻辑
- 在 FlagDependencyUsagePlugin 插件中,从 entry 开始逐步遍历 ModuleGraph 存储的所有 module 对象
- 遍历 module 对象对应的 exportInfo 数组
- 为每一个 exportInfo 对象执行 compilation.getDependencyReferencedExports 方法,确定其对应的 dependency 对象有否被其它模块使用
- 被任意模块使用到的导出值,调用 exportInfo.setUsedConditionally 方法将其标记为已被使用。
- exportInfo.setUsedConditionally 内部修改 exportInfo._usedInRuntime 属性,记录该导出被如何使用
2、最终通过 ConcatenatedModule.codeGeneration 生成 ESM 的代码,最后通过 JavaScriptModulesPlugins.renderMain 生成最终的代码
编辑切换为居中
添加图片注释,不超过 140 字(可选)
在此之后,将由 terser-webpack-plugin “摇”掉这部分无效代码,构成完整的 Tree Shaking 操作。
代码编写中支持 tree shake
1、使用#pure标注纯函数调用, /#PURE/ console.log('000'); 会被shake 掉
2、使用支持 Tree Shaking 的包
3、导出推荐
const a = '1'
const b = '2'
export {
a,
b
}