秋天的奥林匹克森林公园
在项目中引入 lodash 后,通过分析打包资源发现 lodash 的体积过大。为了优化包体积,我们决定通过配置 package.json 中的 sideEffects 字段来启用摇树优化(Tree Shaking)。
然而在启用摇树优化后,出现了两个问题:
在 package.json 中将 CSS 文件标记为有副作用:
"sideEffects": [
"**/*.css"
]
对于没有导出任何内容(没有 export)但需要被执行的模块,需要将其添加到 sideEffects 配置中:
"sideEffects": [
"./src/utils/resetFontSize.ts"
]
sideEffects 字段用于标记哪些文件具有副作用。打包工具在进行摇树优化时,主要遵循以下步骤:
ESModule 进行静态分析,识别未被引用的模块webpack 依赖的 terser 会去检测语句中的副作用(但 JS 作为动态类型语/*#__PURE__*/ 来sideEffects 配置项中告诉打包工具哪些文件是有副作用的,/*#__PURE__*/ 来辅助标记无副作用的代码。以下是一个典型的问题示例:
// resetFontSize.ts
import { detectDeviceType } from './deviceUtils';
(function flexible(window: Window, document: Document) {
function resetFontSize() {
const clientWidth = parseInt(
document.documentElement.clientWidth.toString(),
10
);
let size = 0;
// 使用 detectDeviceType 函数判断设备类型
if (detectDeviceType() === 'desktop') {
size = (document.documentElement.clientWidth / 1920) * 16;
document.documentElement.style.fontSize = (size <= 14 ? 13 : size) + 'px';
} else {
size = clientWidth;
const fontSize = (size / 750) * 16;
document.documentElement.style.fontSize = fontSize + 'px';
}
}
resetFontSize();
window.addEventListener('pageshow', resetFontSize);
window.addEventListener('resize', resetFontSize);
})(window, document);
// index.ts
import '@utils/resetFontSize';
虽然 index.ts 中引用了 resetFontSize,但由于该模块没有任何 export,摇树优化会将其删除。解决方案是在 sideEffects 中声明:
// package.json
"sideEffects": [
"./src/utils/resetFontSize.ts"
]
对于 Vue 项目,如果组件中包含样式,需要特别处理:
// package.json
"sideEffects": [
"**/*.css",
// 标记包含样式的 Vue 组件
"./src/ComponentWithStyle.vue"
]
另外,也可以选择完全禁用摇树优化,即从 package.json 中移除 "sideEffects": false。
为了更好地利用摇树优化:
lodash-es 替代 lodashsideEffects 中声明/*#__PURE__*/ 注释标记无副作用的代码