清理和加速 JS 生态系统——迄今为止的历程
一段时间以来,我一直致力于提升整个生态系统的性能。通常是通过清理老化的依赖树、减少安装占用空间以及提高常用依赖项的 CPU/内存性能来实现的。
这篇博文只是我尝试简要解释一下促成e18e和生态系统清理的一些历程。
关于微型公用事业的思考
微型实用程序是许多项目安装包大小以及依赖关系树复杂性的主要贡献者。
is-number诸如此类的包裹is-nan就属于这一类。
重要的是,这些软件包中的许多在某些情况下确实有用,但在常见情况下肯定没有用处。
通常情况下,在以下情况下它们可以被替换:
- 它们编写于原生功能尚未实现的年代,但现在已经有了。
- 他们提供的服务远超消费者所需。
示例:is-number
例如,is-number判断一个值是数字还是类似数字的字符串(非NaN空字符串+/-Infinity)。
在某些项目中,这是一项重复的验证工作,最好将其提取到一个单独的模块或包中。
然而,在通常情况下,许多消费者根本不需要验证NaN,Infinity甚至不需要支持类似数字的字符串。
这为各种项目带来了一些改进的可能性。我们可以用更简单的内联逻辑来替代这些项目中对该软件包的使用(例如,在许多实际项目中,我们安全地切换到了另一种方式,typeof n === 'number'因为这些项目后来都假定并依赖于该值是一个实际的数字)。
另一个例子:is-regexp
你可以使用冒号 ( :)来测试某个东西是否是正则表达式instanceof。v instanceof RegExp
然而,在某些情况下(例如使用虚拟上下文时),这种方法行不通,因为RegExp它并非v源自同一个类。在这种情况下,我们需要使用类似这样的方法:
Object.prototype.toString.call(obj) === '[object RegExp]'
如果你不想内联这类代码,并且需要支持虚拟上下文或类似概念,那么使用库可能更合适。
然而,在很多情况下,这些项目本身就不支持虚拟环境(而且也不想支持)。这为我们提供了再次简化为简单版本的机会instanceof。
支持旧版运行时
另一个潜在的改进领域是旧版运行时支持。
许多非常流行的软件包都存在非常深的依赖关系树,其中包含各种类似 polyfill 的模块。这种情况通常出于以下一个或两个原因:
- 为了防止全局命名空间被篡改
- 为了在缺少此功能的运行时环境中保持支持
我们中的许多人并不需要这种程度的向后兼容性,如果能够去掉它,就能获得巨大的性能提升。
当然,值得注意的是,仍然有人需要在这些限制条件下工作。因此,在这个领域,我们通常会提供分支或替代方案,而不是试图修改现有的软件包(反正这些软件包也不允许进行此类修改)。
情况开始好转
大约在 2018 年,我开始思考这些特定领域,因为我发现node_modules即使是最小的项目,我的代码也相当庞大且嵌套很深。
我最初几次尝试修改代码,是想创建一个 ESLint 插件,用来检测这些软件包并建议移除它们。每隔几个月,我都会冒出同样的想法并再次尝试,但始终未能达到预期效果。
在此期间,我至少参与了各种大型项目,尽我所能地进行清理和改进(例如,我长期以来参与的一个项目是storybook)。
生态系统清理
之后我创建了生态系统清理库,这是一个用于提出整个生态系统中可能的性能改进建议的仓库(本质上是一个问题跟踪器)。同样,在一段时间内,这基本上只是我个人的问题跟踪器,但至少它是公开的。
不久之后,我开始看到有人参与到问题讨论中,并为上游项目做出贡献。看到这些我非常高兴,因为我多年来一直独自埋头苦干,却始终怀疑自己是否真的有所作为。看到其他人也加入进来,让我知道有人关心这个问题,这给了我莫大的安慰。
模块更换
虽然清理项目过去和现在都非常有用,但我们并没有真正向社区其他成员分享有哪些好的替代方案。
为了解决这个问题,我创建了模块替换项目。
该项目主要包含一些 JSON 列表,其中列出了可能被替换的模块及其建议的替代方案。这些模块目前根据“严格程度”或“倾向性”分为三个级别:原生模块(可以用原生功能替换的模块)、微工具模块(可以用简单的内联代码替换的模块)和推荐模块(我们认为应该用性能更高的替代方案替换的模块)。
Codemods
替换项目的下一步是创建一套代码转换程序,以便我们可以自动替换其中一些模块。
在@passle的推动下,该项目迅速获得了大量以各种代码修改形式提交的贡献。
CodeMod团队在将这些功能移植到 CodeMod 平台方面也做得非常出色。未来,我们也希望通过某种命令行界面 (CLI) 或自动修复规则来提供这些功能。
e18e
我觉得所有关心这些事情的人找到彼此的转折点是e18e。
Bjorn在提升astro的性能方面做了很多出色的工作,而Marvin也一直在撰写关于加速生态系统的文章。最终,我们相遇了,并进行了一些非常有益的私下交流。
我们一小群人聚在一起,看看我们是否意见一致,以及能否以此为基础建立一个社区。然后,e18e就出现了!
这个平台旨在打造一个供人们协作提升生态系统性能的社区空间,它让我们看到了有多少人关心这些问题。许多人已经加入并做出了巨大的贡献。我们几乎每天都能看到整个生态系统的速度提升和规模缩小。
非常感谢
社区发展迅速,贡献者众多,在此无法一一感谢。但我特别想感谢以下几位,感谢他们让这个社区成为可能:
同样,那些已经在并行开展旨在实现相同目标的项目的人员:
- @asleMammadam通过 tinylibs
- @pi0通过 unjs