JavaScript 包管理的前世今生

npm / Yarn

和 Yarn 相比,npm 在缓存、集成度和扩展性方面表现如何呢?我们将在这篇文章中一辨分晓。

如果将一个 JavaScript 开发者在 2005 年冰冻起来,然后在 2017 年的现在以某种神奇的方式将其解冻,那么 JavaScript 包的爆炸式繁荣将会令他震惊。下方的视频以一种炫酷的视觉展现方式向我们重现了这些包是如何随着时间爆炸式繁荣起来的。
youtube视频

从大型的框架库,到解决某个问题的小型函数包,如今的 JavaScript 生态系统几乎囊括了每一个需求所需要的包。JavaScript 作为一个强大而流行的编程语言,这种组件化的代码包对 JavaScript 的发展进化至关重要。随着包的增多,开发者也看到了对于高性能、安装管理包依赖的稳定的包管理器的需求。

我们这个系列的第一篇文章中,已经讨论了 JavaScript 的革命,并介绍了现代前端开发中的三个核心部分:包管理器、应用打包和语言规范。本文会聊聊包管理器是如何出现、如何发展的,聊聊针对于可扩展应用,在未来包管理的革命道路上 Kenzan 为什么推荐使用 Yarn 来作为包管理器。

包管理器横空出世

随着包管理器横空出世,开发者放弃了下载包并手动引入所需文件的原始方式,作为领先者的 npm(v2)和 Bower 开始崭露头角。

在那个时候,npm 只能处理 node 包。在 npm 早期的版本中,处理像 HTML 和 CSS 这样的前端静态资源还是比较罕见的。相反,Bower 就是专门为处理像 HTML、CSS 和 JS 这样的前端静态资源而诞生的。对于早期的前端项目 Bower 是一个极有价值的工具。Bower 拥有一套自己的前端包安装源,并且提供了一个扁平化的依赖关系树,在遇到冲突时,可以让用户来决定他们想要的版本。它为包管理功能开创了先河,并使 JavaScript 走向包繁荣的道路。

随着应用的变重和依赖库数目的增长,这个基础开始崩溃。版本不匹配的问题越来越难处理。使用 Bower 构建需要 wiredep 和大量的配置。而且,最重要的问题是,CommonJS 和其他的模块规范并不能得到很好的支持。像 webpack™ 这样的模块加载器曾经也很难处理 Bower 包合并和打包的格式,偶尔还会出现完全无法将它们模块化的情况。随着模块化的 JavaScript 逐渐崛起,这成为了一个突出的问题。

针对这些问题,npm 发布了 v3 版本。它提供了一个扁平化的依赖关系树,拥有针对冲突的模块嵌套、CommonJS 模块支持、以及可以同时用于前端包和 node 包的单一生态系统等特性。总体来说,对于 npm ,这是一个巨大的成功,npm 被大量的应用于 JavaScript 社区。但是,这个系统很快就在项目中暴露出了缺陷。首先,npm v3 和 v4 在安装包时的一致性并不确定,这就意味着模块并不总是以相同的顺序或嵌套模式安装。对于开发者来说,node 模块漂移会导致一些类似于“这个项目在我电脑上完全可以正常运行啊”之类的臭名昭著的 bug。第二个问题就是缓存。npm 缓存并不可靠,损坏的部分会被移除掉而不会被替代。这就意味着,开发者不能依赖当前的缓存来作为之后的安装,离线安装是没有问题的。

我们也看到像 JSPM 这样的新的包管理器开始出现。JSPM(JavaScript Package Manager的缩写) 是作为 SystemJS 的一个工具而出现的。这两个软件包试图通过清理整合到软件包管理来处理 JS 模块加载。JSPM 可以通过 npm 源、GitHub 和私有源来安装依赖,然后更新 SystemJS 配置以映射到新模块,这样便可以跨文件导入。尽管包管理和模块加载有一些共同的关注点,但它们似乎并没有足够同步,因此需要显式地配对。另外,如果要同时使用这两个工具来构建应用,配置是非常困难的。而且随着 webpack 的流行普及,JSPM 开始失去支持。随着 Angular CLI 用 webpack 替换 SystemJS,JSPM最终宣告失败。

半路杀出个 Yarn

Yarn 在 2016 年年底由 Facebook 推出,是为了解决上述提到的一些 npm 的常见问题。Yarn 受 npm 的启发,依赖巨大的 npm 源和 package.json 文件,使得应用扩展具无痛的可重复性。在开发者使用同一版本 Yarn 的情况下,Yarn 使用一个自定义的锁文件(lockfile)和安装算法来确保安装软件包的一致性。这就保证了无论开发者选择什么样的方式来安装,都能够拥有完全相同的 node 包。再也没有软件包漂移,再也没有隐藏的 bug!这也意味着开发人员和 CI (持续集成)环境之间的一致性。

而且,针对 node 包,Yarn 提出了一种缓存机制。使用暖缓存(warm cache),Kenzan 的安装速度有了 4 倍的提升。更快的安装意味着更快的构建和更快的开发。缓存也支持沙盒安装和离线安装。因为它可以防止在安装期间注入任何恶意内容,所以这些特性对于企业级应用的重要性正在日益增加。因为软件包会被缓存和检查,所以之后从缓存中安装包也是安全的。

在 Kenzan,相比于 npm,我们大量使用了 Yarn 为我们的客户端应用进行构建,充分利用了 Yarn 构建的一致性、安装时间短、沙盒安装的相关特性。这些改变带来的效果就是,我们 CI/CD(持续集成/持续交付)过程出现的问题更少了,安装速度更快了。对于我们的客户端应用而言,这意味着更少的资金投入、更少的不知所踪的隐形的 bug。

但是这并不是说 Yarn 完美得没有一点儿缺点。它确实存在着一些问题,比如对于私有 npm 包的支持有限,从 GitHub 上拉取软件包也存在着一些问题。如果这些问题对于一个项目来说影响很重要,那么 Yarn 可能并不是你的正确选择。但是,相比于 npm,Yarn 社区的开发支持水平一直很高,通过 PR 提交的 bug 很快就能被修复。我们预期 Yarn 很快就能覆盖 npm 的所有功能。

npm 重出江湖!

今年春天,npm 发布了 v5 版本,这使得包管理器和 Yarn 的竞争更加激烈。这样的话就出现了一个有趣的问题,对于那些已经选择了 Yarn 作为构建工具的开发人员来说,是接着使用 Yarn 呢,还是放弃 Yarn 改用 npm 呢?

虽然没有对比就没有伤害,但是为了能够做出明智的选择,我们觉得有必要跑一些测试用例来做些研究。 npm v5 的确像他们说的那样快吗?和 Yarn 相比,npm 在缓存、集成度和扩展性方面表现如何呢?

首先,我们先来测试下速度。我们使用 create-react-app 项目进行了安装速度测试。我们比较了 npm v4、Yarn、npm v5,最后两条数据是使用暖缓存(warm cache)的情况。对于每一项,我们都跑了 10 次测试,以适应不同的网络条件。下面是我们的结果。

6ZqbjTpna1ddmzVgexCH8RP__M68He7nhjWKErPn

npm v5 确实很快,几乎是 npm v4 的四倍!在冷安装(cold install)的情况下甚至比 Yarn 还要快,但也只是快了一丢丢。在速度方面真正脱颖而出的是在暖缓存(warm cache)情况下的 Yarn,比 npm 快了足足两倍。这个测试的结论如下:是的,npm v5 与以前的版本相比确实表现出了强大的性能优势,但与 Yarn 相比,缓存安装速度仍然略逊一筹。

接下来,我们来看看缓存机制。上一个版本的 npm 存在着一个巨大的痛点:缓存不一致。针对这一点,新版 npm 貌似已经解决了。npm 新版的缓存是自我修复的,就是说,当损坏的数据被删除时,它会自动重新安装,并且安装失败时会重试。这意味着,新版 npm 可以做到缓存安装的一致性,这一点和 Yarn 类似。

在可用性和集成度方面,老版本 npm 曾经扯过后腿。新版本 npm 的 lockfile 文件包含了所有包的确定性列表,其中将根级别包升级到树的顶部,因此可以使用该文件完成完整安装。对于一致性安装,Yarn 需要 yarn.lock 和 package.json。由于它们都是由 npm 团队创建的,所以 npm 与私人软件包源和软件包发布可以无缝集成。

最后,我们研究了扩展性。在这一点上,两个包管理器在扩展大型企业应用时具有类似的功能。但是,Yarn 的初衷就是为了大型应用而设计的包管理器,并为此而持续发展的。它优先考虑了高级注册功能的规模和安全性问题(尽管这些问题仍然在持续解决中)。Yarn 很可能会引领大规模应用改进的潮流。

我们该何去何从

这个系列的第一篇文章中,我们说过,所有的项目应该只使用一个包管理器。以我们的经验,我们发现,使用工具保证跨机器的一致性有助于创建重用性好、bug 少的应用。但是至于你选择哪个就应该考虑到你的团队所开发项目的类别了。

随着 npm v5 的发布,npm 可能是一个好的选择。对于小型项目,它提供了和 Yarn 几乎相同的速度,跨机器也可以做到完全一致性。对于私有的 npm 包和 GitHub 仓库,它的 bug 也更少,社区修复 bug、开发新特性也维持在一个充足的水平。在我们看来,它适用于规模较小、不太需要扩展的小型应用。

但是,在 Kenzan,我们关注的是具有最大限度可扩展性的大型企业应用。考虑到这些限制,Yarn 已经被证明是个明智的选择。它给我们提供了快速构建的速度、依赖包的一致性,社区改进特性、开发新特性也很活跃。无论一个应用有多少开发者,无论处于什么环境下,只要使用 Yarn,我们就能保证可扩展性。正是因为这些原因,我们选择 Yarn 作为我们唯一的包管理器,同时我们也推荐你尝试一下。

请继续关注我们的下一篇博客文章,我们将通过探索打包模块的工具,将我们的前端技术栈进一步扩展。

译者注:以下是原作者对自己所在公司的介绍,译文保留。

Kenzan 是一家软件工程和全面服务咨询公司,提供通过数字化转换来驱动的定制的端到端解决方案。Kenzan 结合领导力与技术专长,与合作伙伴和客户展开合作,利用前沿技术,提供从理念到开发到交付的完整的解决方案。Kenzan 是一家技术驱动公司,专业从事应用和平台开发、架构咨询和数字化转换。

webpack 是 JS Foundation 的商标。

1 收藏 评论

可能感兴趣的话题



直接登录
跳到底部
返回顶部