Webpack 等构建工具通过 Tree Shaking (摇树优化)和 Dead Code Elimination(无用代码消除)技术来移除未使用的代码。以下是具体实现原理、配置方法及最佳实践:
一、Tree Shaking 的原理
Tree Shaking 是一种基于 ES Module(ESM)静态语法结构 的代码优化技术,通过静态分析确定模块中哪些导出未被使用,并将其从最终产物中移除。
关键条件:
- 使用 ESM 语法 (
import/export
),而非 CommonJS(require/module.exports
)。 - 标记无副作用代码 :通过
package.json
的sideEffects
属性或注释声明文件是否包含副作用。 - 生产模式优化:压缩工具(如 Terser)配合 Webpack 删除未引用代码。
二、Webpack 的 Tree Shaking 配置
1. 基础配置
javascript
// webpack.config.js
module.exports = {
mode: 'production', // 生产模式自动启用优化(包括 Tree Shaking)
optimization: {
usedExports: true, // 标记未被使用的导出
minimize: true, // 启用压缩(删除未使用代码)
},
};
2. 确保模块为 ESM 格式
-
Babel 配置 :避免将 ESM 转换为 CommonJS。
javascript// .babelrc { "presets": [ ["@babel/preset-env", { "modules": false }] // 保留 ESM 语法 ] }
3. 声明无副作用文件
在库的 package.json
中标记无副作用的文件或目录:
json
{
"sideEffects": false, // 整个包无副作用
"sideEffects": ["*.css"], // 仅 CSS 文件有副作用
}
三、Rollup 的 Tree Shaking
Rollup 默认支持 Tree Shaking,无需额外配置,但需注意:
- 使用 ESM 语法。
- 避免副作用代码(如立即执行的全局操作)。
javascript
// rollup.config.js
export default {
input: 'src/main.js',
output: {
file: 'dist/bundle.js',
format: 'esm',
},
treeshake: true, // 默认启用
};
四、Vite 的 Tree Shaking
Vite 基于 Rollup 和 esbuild,默认在生产模式下启用 Tree Shaking:
javascript
// vite.config.js
export default {
build: {
minify: 'terser', // 启用压缩
},
};
五、场景示例
1. 移除未使用的函数
javascript
// math.js
export function add(a, b) { return a + b; }
export function sub(a, b) { return a - b; }
// main.js
import { add } from './math.js';
console.log(add(1, 2)); // 未使用 sub 函数
打包结果 :sub
函数被移除。
2. 处理第三方库
若第三方库支持 Tree Shaking(如 Lodash ES 版本):
javascript
import { debounce } from 'lodash-es'; // 仅打包 debounce
若库未优化(如旧版 Lodash):
javascript
import debounce from 'lodash/debounce'; // 直接导入子模块
六、常见问题与解决方案
1. Tree Shaking 失效的可能原因
- 模块语法问题 :使用 CommonJS(如
require
)而非 ESM。 - 副作用代码干扰 :未正确标记
sideEffects
,导致构建工具误保留代码。 - Babel 转换破坏 ESM:配置错误将 ESM 转为 CommonJS。
2. 如何验证 Tree Shaking 是否生效?
- 打包产物分析 :使用 Webpack Bundle Analyzer 检查未使用的模块。
- 控制台输出 :在 Webpack 配置中启用
usedExports: true
,查看日志中标记的未使用导出。

3. 如何处理 CSS 中的未使用代码?
-
使用工具如 PurgeCSS 删除未使用的 CSS:
javascript// webpack.config.js const PurgeCSSPlugin = require('purgecss-webpack-plugin'); const glob = require('glob'); module.exports = { plugins: [ new PurgeCSSPlugin({ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), }), ], };
七、最佳实践
- 统一模块规范:全项目使用 ESM 语法。
- 按需引入第三方库 :优先选择支持 Tree Shaking 的 ESM 版本(如
lodash-es
替代lodash
)。 - 标记副作用 :在
package.json
中明确声明副作用文件。 - 压缩代码:启用 Terser 或 esbuild 删除未引用代码。
- 持续监控:通过分析工具定期检查打包结果。
总结
通过合理配置 Webpack、Rollup 或 Vite 的 Tree Shaking 功能,结合 ESM 语法和副作用标记,可以有效移除未使用的代码,显著减少打包体积,提升应用性能。