阅读更多

1顶
0踩

编程语言

转载新闻 JavaScript 包管理的前世今生

2017-08-03 10:58 by 副主编 jihong10102006 评论(0) 有6664人浏览
编者按:本文由myvin在众成翻译平台上翻译。JS生态系统的繁荣离不开强大的包管理工具,今天我们来看看JavaScript 包管理的进化过程。

(图片来自网络)


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

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

从大型的框架库,到解决某个问题的小型函数包,如今的 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 次测试,以适应不同的网络条件。下面是我们的结果。

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 作为我们唯一的包管理器,同时我们也推荐你尝试一下。
  • 大小: 761.7 KB
  • 大小: 42.7 KB
  • 大小: 267.8 KB
  • 大小: 50.9 KB
1
0
评论 共 0 条 请登录后发表评论

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • JavaScript 异步编程的前世今生(下)

    不过不要惊慌,也不要请如来佛祖,跟着我的节奏来,认真看,一天包教包会是没问题的! 接下来... 接下来我们不会立刻讲解如何使用Generator做异步操作,而是看一看Generator是一个什么东西!说来话长,这要从 ES6 的...

  • Webpack前世今生

    index.html:浏览器打开展示的首页html package.json:通过npm init生成的,npm包管理的文件(暂时没有用上,后面才会用上) mathUtils.js中的代码: function add(num1,num2){ return num1+num2; } function mul...

  • 前端模块化的前世今生

    } script> 或 <script type="text/javascript" src="calAverageScore.js">script> <script type="text/javascript" src="calTotalScore.js">script> 在无模块化的时代,开发者想要引用别人的代码要么只能把别人的...

  • JNDI 注入漏洞的前世今生

    使用目录服务可以简化应用中服务管理验证逻辑,集中存储共享信息。在 Java 应用中除了以常规方式使用名称服务(比如使用 DNS 解析域名),另一个常见的用法是使用目录服务作为对象存储的系统,即用目录服务来存储和...

  • Nginx的前世今生

    Nginx的前世今生1.Nginx的概述2.Nginx在Linux下的安装2.1 环境准备2.2 Nginx下载2.3 Nginx安装 (tar)包2.4 Nginx启动与访问2.5 docker-compose启动3. Nginx静态网站部署3.1 什么是虚拟主机?3.1.1 Nginx 配置文件的...

  • 详细HTTP协议的前世今生

    它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以ASCII形式给出;而消息内容则具有一个类似MIME的格式 ... 七、HTTP 连接管理 八、无状态的 HTTP 九、HTTP 断点续

  • JS模块化的前世今生

    java风格的命名空间 为了避免全局变量造成的冲突,人们想到或许可以用多级命名空间来进行管理,于是,代码就变成了这个风格: app.util.modA = xxx; app.tools.modA = xxx; app.tools.modA.format = xxx; Yahoo的...

  • JS模块化的'前世今生'

    一、模块化定义 模块,又称构件,是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合...JavaScript模块的前世今生: https://yanhaijing.com/javascript/2015/03/28/js-module/

  • mysql回调地狱_JavaScript 中回调地狱的今生前世

    1. 讲个笑话JavaScript 是一门编程语言2. 异步编程JavaScript 由于某种原因是被设计为单线程的,同时由于 JavaScript 在设计之初是用于浏览器的 GUI 编程,这也就需要线程不能进行阻塞。所以在后续的发展过程中基本...

  • webRTC前世今生

    WebRTC 的前世今生 本文由rwebrtc翻译 WebRTC 技术是激烈的开放的 Web 战争中一大突破。-Brendan Eich, inventor of JavaScript 无插件实时通信 想象一下手机、TV 和电脑都通过统一平台进行沟通。试想...

  • 了解微前端,深入前端架构的前世今生

    比如: 后端框架:express、koa 包管理工具:npm、yarn node版本管理:nvm 综上,大前端时代给我们提供了一定的便利,但同时也带来了一定的弊端。比如: 所有的代码基本都可以通过应用拆分来实现细颗粒度,但是呢,...

  • HTTP 的前世今生

    POST 到 GET 的重定向 4xx 客户端错误状态码 400 客户端参数错误 401 没有登录 403 登录了没权限 比如管理系统 404 页面不存在 405 禁用请求中指定的方法 5xx 服务端错误状态码 500 服务器错误:服务器内部错误,...

  • CSS => CSS的前世今生浅谈

    早期 CSS 的语法设计看上去类似后来的 JavaScript 语法(当时 JavaScript 尚未存在),实际上,CSS 的这个写法借鉴了 X11 Window System 中的 X 资源。 早期CSS语法提案 在第一稿建议中,有一个影响百分比的...

  • Python的前世今生

    已经没有什么能够阻挡 Python 了,已经没有什么能够阻挡 Python 了Python的前世Python的诞生Python的创始人吉多·范罗苏姆(Guido van Rossum),在1989年12月的圣诞节期间,为了打发时间,决定开发一种新的脚本解释...

  • WebSocket 前世今生

    基于 Flash,AdobeFlash 通过自己的 Socket 实现完成数据交换,再利用 Flash 暴露出相应的接口为 JavaScript 调用,从而达到实时传输目的。此方式比轮询要高效,且因为 Flash 安装率高,应用场景比较广泛,但在移动...

  • 前端开发的前世今生

    JavaScript 先天不具有其它语言的包管理功能,components、bower、spm这类技术栈为我们解决了包管理问题,目前npm 开始主导整个市场。 其他前端技术 ECMAScript 6 ES6(ECMAScript2015)的出现,...

  • Git分支的前世今生

    导读 几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。 在很多版本控制系统中,这是一个略微低效的过程——常常需要完全创建一个源代码目录...

  • Java的前世今生(二)

    Java的前世今生(二) Java ​ 今日在喝咖啡的时候,不知不觉想起了Java,想起了以前的一些往事。Java 1995 年正式诞生起到现在,已经快 23 年了。我从2002年开始接触Java,它已经陪我已走过了15个年头,当年记得我...

  • setting.xml文件,修改Maven仓库指向至阿里仓

    setting.xml文件,修改Maven仓库指向至阿里仓

Global site tag (gtag.js) - Google Analytics