Tree Shaking 与 sideEffects
如果你希望你的代码或开源库能够被正确地 Tree Shaking(让打包器在最终产物中自动移除未被使用的导出),需要显式告诉构建工具:哪些文件“不会在被引入时产生副作用”。最常见的做法是在 package.json 中配置 sideEffects:
- 绝大多数纯 JS/TS 工具库:可以设置为
"sideEffects": false。这表示你的模块在被import时不会执行影响外部环境的行为(例如修改全局变量、注册 polyfill、自动打补丁、向window挂载属性、自动注入样式等)。这样 Webpack/Rollup 等工具就更敢于删除“只引入了但未使用”的文件,从而获得更好的 Tree Shaking 效果。 - 确实有副作用的文件:不要一刀切地设为
false,否则可能导致样式或初始化逻辑被错误裁剪。你可以把sideEffects配置成数组白名单,例如:
简单来说:sideEffects 的目的不是“优化一定更快”,而是让打包器在保证行为正确的前提下,尽可能安全地移除无用代码。
什么是 Tree Shaking?
Tree Shaking 是打包工具(Webpack/Rollup/esbuild)在生产构建时自动删除未使用的导出代码的优化手段。它依赖 ES Module 的静态结构分析。
sideEffects 配置详解
package.json 配置
{
"name": "my-library",
"sideEffects": false
}
// 或者指定有副作用的文件
{
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfill.ts",
"./src/register-global.ts"
]
}
什么算”副作用”?
- 修改全局变量(window.xxx = …)
- 注册 polyfill(import “core-js/stable”)
- CSS/SCSS 文件的引入(import “./style.css”)
- 立即执行的函数表达式(IIFE)且影响外部状态
- 模块顶层的 console.log / fetch 等调用
什么不算”副作用”?
- 纯函数定义和导出
- 类型定义和接口声明
- 常量定义(export const FOO = 1)
- 纯计算逻辑(不依赖/修改外部状态)
Webpack 中的 Tree Shaking
// webpack.config.js
module.exports = {
mode: 'production', // 生产模式自动启用
optimization: {
usedExports: true, // 标记未使用的导出
minimize: true, // 压缩时删除标记的代码
sideEffects: true, // 读取 package.json 的 sideEffects
},
};
常见问题与排查
问题 1:CSS 被错误删除
// ❌ 设置了 sideEffects: false,CSS import 被当作无副作用删除
import './button.css';
// ✅ 解决:将 CSS 加入白名单
// package.json: "sideEffects": ["*.css"]
问题 2:类的静态属性导致无法 Tree Shake
// ❌ 类的静态属性赋值被视为副作用
class MyComponent {
static displayName = 'MyComponent'; // 这行是副作用!
}
// ✅ 添加 /*#__PURE__*/ 注释
const MyComponent = /*#__PURE__*/ (() => {
class MyComponent {}
MyComponent.displayName = 'MyComponent';
return MyComponent;
})();
问题 3:barrel file(index.ts 重导出)影响 Tree Shaking
// ❌ src/index.ts(barrel file)
export { Button } from './Button';
export { Modal } from './Modal';
export { Table } from './Table';
// 即使只用了 Button,Modal 和 Table 的初始化代码也可能被保留
// ✅ 直接从具体模块导入
import { Button } from 'my-lib/Button';
验证 Tree Shaking 效果
- 使用 webpack-bundle-analyzer 查看打包结果
- 检查构建产物中是否包含未使用的模块
- 使用 sideEffects-analysis 工具分析项目副作用
# 安装分析工具
pnpm add -D webpack-bundle-analyzer
# 在 webpack 配置中添加
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins: [new BundleAnalyzerPlugin()]