跳到主要内容

Tree Shaking

2025年01月09日
柏拉文
越努力,越幸运

一、认识


Tree Shaking 是一种优化技术,用于去除 JavaScript 中未被使用的代码,减少最终打包文件的大小,提高应用加载速度。在基于 Webpack 的项目中,配置 Tree Shaking 主要通过以下几个步骤完成。

二、操作


2.1 确保使用 ESM

Tree Shaking 是基于 ES6 模块(importexport)来工作的。CommonJSAMD 模块格式不支持静态分析,因此不能有效地进行 Tree Shaking

2.2 启用生产环境构建

Tree Shaking 主要作用在生产环境中。Webpack 会在生产模式下自动移除未使用的代码(例如,unused 的函数、变量等)。因此,确保 Webpack 配置中的 mode 设置为 production

module.exports = {
mode: 'production', // 开启生产模式
...
};

2.3 配置 optimization.usedExports

Webpack 中,optimization 配置项会影响到 Tree Shaking 和代码压缩。你需要确保以下设置:

  • usedExports:确保 Webpack 知道哪些导出是被使用的。

  • minimize:启用代码压缩,这可以帮助进一步去除未使用的代码。

module.exports = {
mode: 'production',
optimization: {
usedExports: true, // 启用 Tree Shaking
minimize: true, // 启用代码压缩
// 可选:启用内联的最小化代码
minimizer: [
// 使用 TerserPlugin 进行压缩
new TerserPlugin({
terserOptions: {
ecma: 2015, // 使用 ES2015 的特性进行压缩
},
}),
],
},
};

2.4 配置 package.json.sideEffects

Tree Shaking 是基于静态分析的,它会去除那些不被使用的代码。如果某个模块或文件在执行时有副作用(例如修改全局变量、日志输出等),即使它没有被显式使用,Webpack 也可能无法完全移除它。这是因为 Webpack 无法确定这些副作用是否会在其他地方使用。在 package.json 中使用 sideEffects 字段来指明哪些文件是有副作用的,Webpack 会根据这个字段来优化 Tree Shaking

{
"sideEffects": [
"src/styles.css", // 告诉 Webpack 该 CSS 文件有副作用,不应该被 Tree Shaking 去除
"*.css", // 或者标明所有 CSS 文件都有副作用
]
}

三、CommonJS Tree Shaking


许多较老或以 CommonJS 格式发布的第三方库并不支持 Tree Shaking。即使你正确配置了 Webpack,如果你的依赖库没有使用 ES6 模块或正确的导出方式,Webpack 也无法进行有效的 Tree Shaking

Webpack 中,Tree Shaking 是一种优化机制,通过静态分析模块的引用,去除未使用的代码。对于 ES ModulesWebpack 能够通过静态分析 importexport 语法来实现 Tree Shaking,因为这些语法是静态的,Webpack 可以在编译时清晰地了解模块的依赖和导出。然而,CommonJS 模块的 requiremodule.exports 是动态的, 运行时同步加载。Webpack 很难静态分析这些模块,因此 Tree Shaking 效果通常较差。

3.1 将 CommonJS 转换为 ESM

如果你使用 Babel 来编译 JavaScriptbabel-plugin-transform-modules-commonjs 插件可以将 ES Modules 转换为 CommonJS 格式,这样有时能解决一些 Tree Shaking 的问题,尤其是当你使用的第三方库没有提供 ES 模块版本时。

{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/preset-env",
{
modules: "commonjs", // 转换为 CommonJS 模块
targets: "defaults", // 可以根据项目的目标环境调整
},
],
],
plugins: ["@babel/plugin-transform-runtime"]
},
}
}

3.2 模拟 ESM 模块的 Tree Shaking

webpack-common-shake 是一个针对 CommonJS 模块优化的插件,它通过分析模块中的导出和引用,尽量减少打包文件中的冗余代码。这个插件的目的是模拟 ES 模块的 Tree Shaking,尽可能地优化 CommonJS 模块。

webpack-common-shake 是一个针对 Webpack 的插件,旨在提升 CommonJS 模块的 Tree Shaking 效率,尽管 Webpack 本身对 CommonJS 模块的 Tree Shaking 支持有限。该插件的核心目标是模拟 ES ModulesTree Shaking 行为,通过优化 CommonJS 模块中的导出和引用,使得未使用的代码能够被移除,从而减少打包后的文件体积。

webpack-common-shake 原理如下:

  1. 静态分析模块webpack-common-shake 插件会分析每个 CommonJS 模块的 exportsrequire。它会跟踪每个模块的导出内容,判断哪些导出部分在实际使用中被引用。

  2. 去除未引用的代码: 插件通过追踪依赖关系,去除没有被引用的代码块,这样即使是 CommonJS 模块,也能得到类似于 ES 模块的 Tree Shaking 优化。

  3. 动态导入的处理: 插件还尝试识别和处理动态导入模块(requireimport()),并尽可能地减少冗余代码。

webpack-common-shake 总结: webpack-common-shake 插件能够通过静态分析一定程度上优化这些情况,但它的效果通常较为有限。尤其是在动态 require 难以静态分析: require 是动态的,尤其是在条件语句、循环等结构中,这使得 Webpack 很难确定哪些代码应该被引入,哪些应该被丢弃。同时,对于多个 CommonJS 模块之间复杂的依赖关系,webpack-common-shake 插件可能无法完全解析依赖图,并准确去除未使用的代码。所以,webpack-common-shake 插件在一定程度上帮助 WebpackCommonJS 模块进行 Tree Shaking,但其效果远不如原生支持 ES Modules。对于依赖 CommonJS 的项目,webpack-common-shake 可以优化一些冗余代码,减小文件体积,但并不能像 ES Modules 那样完全利用静态分析来实现高效的 Tree Shaking。因此,最佳的做法仍然是尽量使用 ES Modules,或者将 CommonJS 模块转换为 ES 模块,以便 Webpack 更好地进行优化。

安装:

npm install webpack-common-shake --save-dev

使用:

const CommonShakePlugin = require('webpack-common-shake');

module.exports = {
plugins: [
new CommonShakePlugin()
],
optimization: {
usedExports: true, // 启用用于去除未使用的代码
}
};