tree shaking 在原型挂载(如 object.prototype.xxx = ...)时失效,因其属于顶层副作用,修改全局环境且无法被静态分析判定为可安全删除;应剥离副作用至显式初始化函数,并通过 sideeffects 配置告知构建工具。

Tree Shaking 在对象原型挂载(如 Object.prototype.xxx = ... 或 Array.prototype.map = ...)时会彻底失效,因为这类操作属于**顶层副作用**——它不产生可导出的值,却在模块加载时立即修改全局环境,打包工具无法证明其“可安全删除”,只能保守保留整个模块。
为什么原型挂载会阻断 Tree Shaking
构建工具(Rollup/Webpack/Vite)依赖静态分析判断模块是否“纯”:若一个模块只做 export const a = 1 这类无外部影响的操作,才可能被整块剔除。而原型挂载:
- 发生在模块顶层执行阶段,不依赖 import 调用,无法被引用关系追踪
- 影响全局运行时行为,哪怕业务代码没显式 import 该模块,也可能因其他逻辑间接依赖其副作用
- 破坏了“模块仅用于导出”的静态契约,工具被迫标记为
has side effects
避免原型污染的实用做法
核心原则:**把副作用从模块定义中剥离,推迟到明确需要时再执行**。
-
不直接在导出文件里挂载:删掉类似
String.prototype.trimAll = ...的代码,哪怕它被封装在函数里也不行(函数未调用仍可能被跳过,但挂载语句本身已执行) -
改用显式初始化函数:把挂载逻辑包进一个具名函数,由业务方按需调用
export function polyfillStringTrimAll() {<br> String.prototype.trimAll = function() { return this.trim(); };<br>}
这样,只要没人调用polyfillStringTrimAll(),该模块就不会触发副作用 -
用条件加载控制作用域:在真正需要补丁的组件或页面内调用,而非在 utils 入口统一执行
// product-detail.vue<br>import { polyfillStringTrimAll } from '@/utils/polyfills';<br>polyfillStringTrimAll(); // 只在此处生效 -
优先使用标准替代方案:现代浏览器已支持
String.prototype.replaceAll、Object.hasOwn等,避免自定义挂载;必须兼容旧版时,用独立 polyfill 包(如 core-js),并确保其sideEffects配置精准
配合构建配置加固效果
即使代码层做了隔离,也要让打包工具“信得过”你的模块是纯净的:
- 在对应模块的
package.json中声明:"sideEffects": ["./polyfills/string-trim-all.js"]—— 表示只有这个文件有副作用,其余 JS 文件可放心摇树 - 若整个工具包无任何原型操作,直接设
"sideEffects": false,这是最彻底的声明 - 对已发布的第三方库(如某些老旧 utils 库),可在项目级
webpack.config.js中用optimization.sideEffects: false强制开启激进摇树(需确认无风险)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











