Tree Shaking
一、认识
Tree Shaking
是一种优化技术,用于去除 JavaScript
中未被使用的代码,减少最终打包文件的大小,提高应用加载速度。在基于 Webpack
的项目中,配置 Tree Shaking
主要通过以下几个步骤完成。
二、操作
2.1 确保使用 ESM
Tree Shaking
是基于 ES6
模块(import
和 export
)来工作的。CommonJS
和 AMD
模块格式不支持静态分析,因此不能有效地进行 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 Modules
,Webpack
能够通过静态分析 import
和 export
语法来实现 Tree Shaking
,因为这些语法是静态的,Webpack
可以在编译时清晰地了解模块的依赖和导出。然而,CommonJS
模块的 require
和 module.exports
是动态的, 运行时同步加载。Webpack
很难静态分析这些模块,因此 Tree Shaking
效果通常较差。
3.1 将 CommonJS 转换为 ESM
如果你使用 Babel
来编译 JavaScript
,babel-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 Modules
的 Tree Shaking
行为,通过优化 CommonJS
模块中的导出和引用,使得未使用的代码能够被移除,从而减少打包后的文件体积。
webpack-common-shake
原理如下:
-
静态分析模块:
webpack-common-shake
插件会分析每个CommonJS
模块的exports
和require
。它会跟踪每个模块的导出内容,判断哪些导出部分在实际使用中被引用。 -
去除未引用的代码: 插件通过追踪依赖关系,去除没有被引用的代码块,这样即使是
CommonJS
模块,也能得到类似于ES
模块的Tree Shaking
优化。 -
动态导入的处理: 插件还尝试识别和处理动态导入模块(
require
和import()
),并尽可能地减少冗余代码。
webpack-common-shake
总结: webpack-common-shake
插件能够通过静态分析一定程度上优化这些情况,但它的效果通常较为有限。尤其是在动态 require
难以静态分析: require
是动态的,尤其是在条件语句、循环等结构中,这使得 Webpack
很难确定哪些代码应该被引入,哪些应该被丢弃。同时,对于多个 CommonJS
模块之间复杂的依赖关系,webpack-common-shake
插件可能无法完全解析依赖图,并准确去除未使用的代码。所以,webpack-common-shake
插件在一定程度上帮助 Webpack
对 CommonJS
模块进行 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, // 启用用于去除未使用的代码
}
};