The Three Pillars of JavaScript Bloat
本文分析了JavaScript依赖树中三种主要的"膨胀"类型、它们存在的原因以及如何开始解决这些问题。
支柱一:老运行时支持(安全性和Realm)
为什么我们需要is-string而不是typeof检查?为什么需要hasown而不是Object.hasOwn?三个原因:
- 支持非常老的引擎:ES3环境(IE6/7,早期Node.js)缺少现代JS特性
- 防止全局命名空间被修改:Node.js使用primordials来保护自己不被脚本破坏
- 跨Realm值:iframe和父页面之间的RegExp不是同一个类
问题:这些兼容性层是为极少数人设计的,但却成了"热路径"的一部分。绝大多数开发者不需要这些,但都在为此付出代价。
支柱二:原子架构
一些开发者认为包应该被分解到几乎原子的级别,创建可重复使用的小构建块。
但实际上:
- 单用途包:大多数原子包只有一个消费者,相当于内联代码但获取成本更高
- 重复:同一个包的不同版本在依赖树中重复出现
- 供应链攻击面:包越多,供应链越脆弱(去年一个维护者的多个包被攻击)
支柱三:过时的"Ponyfill"
Ponyfill(相对于polyfill)不会修改全局环境,而是提供条件性导入。但问题是:
- 很多ponyfill包已经是原生支持的特性
- 维护者继续打包这些"未来特性",即使引擎已经支持
- 消费者最终为这些不再需要的polyfill买单
解决方向
这三个支柱都指向同一个方向:需要重新评估何时真正需要依赖。简单如Array.isArray(val) ? val : [val]的逻辑可能不需要自己的包、安全维护等——它可以被内联。