当前位置: 首页 > Web前端 > HTML5

一篇文章搞懂npm、yarn、pnpm的区别

时间:2023-04-04 23:56:58 HTML5

本文作者对比了目前主流的包管理工具npm、yarn、pnpm的区别,并提出了适合的使用建议。以下为译文:NPMnpm是Node.js如此成功的主要原因之一。npm团队做了很多工作来确保npm保持向后兼容和跨环境的一致性。npm是围绕语义版本控制(semver)的思想设计的,以下内容摘自他们的网站:给定一个版本号:主版本号。次版本号。patch版本号,以下三种情况需要增加相应的版本号:Major版本号:当API发生变化,与之前的版本不兼容时Minor版本号:当增加功能时,但向下兼容Patch版本号:当做向下兼容缺陷时npm在修复时会使用一个名为package.json的文件,用户可以通过npminstall--save命令将项目中的所有依赖保存到这个文件中。例如,运行npminstall--savelodash会将以下行添加到package.json文件中。"dependencies":{"lodash":"^4.17.4"}注意版本号lodash前有一个^字符。这个字符告诉npm安装主版本等于4的任何版本。因此,如果我现在运行npm进行安装,npm将安装主版本为4的最新版本的lodash,可能是lodash@4.25.5(@是npm约定用于确定包名称的指定版本)。您可以在此处查看所有支持的字符:https://docs.npmjs.com/misc/semver。理论上,次要版本号的更改不应影响向后兼容性。因此,从4.17.4版开始,安装最新版本的依赖项应该可以工作并引入重要的错误和安全修复。但是,另一方面,即使不同的开发人员使用相同的package.json文件,他们也可能在自己的机器上安装了相同库的不同版本,从而产生潜在的难以调试的错误和“在我的电脑上......“情况。大多数npm库严重依赖于其他npm库,这会导致嵌套依赖并增加无法匹配相应版本的机会。虽然可以使用npmconfigsetsave-exacttrue命令关闭在版本号前面使用^的默认行为,但这只会影响顶级依赖项。由于每个依赖库都有自己的package.json文件,而自己的依赖前面可能有^符号,所以没办法通过package.json文件为嵌套依赖的内容提供保证。为了解决这个问题,npm提供了shrinkwrap命令。此命令将生成一个npm-shrinkwrap.json文件,记录所有库和所有嵌套依赖库的确切版本。但是,即使npm-shrinkwrap.json文件存在,npm也只会锁定库的版本,而不会锁定库的内容。尽管npm现在阻止用户多次重新发布同一版本的库,但npm管理员仍然有权强制更新某些库。这是来自shrinkwrap文档的引述:如果你想锁定包中的特定字节,例如以确保正确的重新部署或构建,那么你应该检查源代码控制中的依赖关系,或使用其他一些机制来验证内容,而不是通过验证版本。npm2将安装每个包依赖的所有依赖项。如果我们有一个项目依赖于项目A,项目A依赖于项目B,项目B依赖于项目C,那么依赖树将是这样的:node_modules-package-A--node_modules---package-B-----node_modules------package-C--------some-really-really-really-long-file-name-in-package-c.js这个结构可能很长。这在基于Unix的操作系统上只是一个小麻烦,但在Windows上却具有破坏性,因为有很多程序无法处理超过260个字符的文件路径名。npm3使用平面依赖树解决了这个问题,所以我们的3个项目结构现在看起来像这样:node_modules-package-A-package-B-package-C--some-file-name-in-package-c.js方式,长文件路径名从./node_modules/package-A/node_modules/package-B/node-modules/some-file-name-in-package-c.js更改为/node_modules/some-file-name-in-package-c.js。您可以在此处详细了解NPM3依赖项解析的工作原理。这种方法的缺点是npm在决定如何生成平面node_modules目录结构之前必须首先遍历所有项目依赖项。npm必须为所有使用到的模块构建一个完整的依赖树,这是一个耗时的操作,也是导致npm安装速度慢的一个很重要的原因。由于我没有详细查看npm的变化,我假设每次运行npminstall命令时,NPM都必须从Internet下载所有内容。然而,我错了,npm有一个本地缓存,里面保存的是已经下载过的每个版本的压缩包。本地缓存的内容可以通过npmcachels命令查看。本地缓存旨在帮助减少安装时间。总而言之,npm是一个成熟、稳定、有趣的包管理器。YarnYarn于2016年10月发布,并迅速在Github上获得24,000个Star。而npm只有12,000个Star。该项目由多名高级开发人员维护,包括SebastianMcKenzie(Babel.js)和YehudaKatz(Ember.js、Rust、Bundler等)。据我所知,Yarn最初的主要目标是解决上一节中描述的由于语义版本控制导致的npm安装的不确定性问题。虽然可以使用npmshrinkwrap来实现可预测的依赖树,但这不是默认选项,所有开发人员都必须了解并启用此选项。Yarn采用不同的方法。每个yarn安装都会生成一个类似于npm-shrinkwrap.json的yarn.lock文件,它是默认创建的。除了一般信息外,yarn.lock文件还包含正在安装的内容的校验和,以确保所使用的库版本相同。由于yarn是一个新的重新设计的npm客户端,它允许开发人员并行化所有必要的操作,并添加了一些其他改进,这使得运行速度显着提高,整体安装时间变得更快。很少。在我看来,速度的提升是yarn流行的主要原因。与npm一样,yarn使用本地缓存。与npm不同,yarn不需要互联网连接来安装本地缓存的依赖项,并且它提供离线模式。这个特性是2012年在npm项目中提出的,但是一直没有实现。Yarn还提供了一些其他的改进,例如,它允许合并项目中使用的所有包的许可证,这非常好。一件有趣的事情是,随着yarn项目的流行,yarn文档的态度开始转向npm。原yarn公告介绍yarn的安装如下:*最简单的入门方式是运行:npminstall-gyarnyarn*当前的yarn安装页面是这样说的:注意:通常不建议通过npm安装。npm安装是不确定的,包没有签名,并且npm除了基本的SHA1哈希之外不执行任何完整性检查,这会给安装系统程序带来安全风险。由于这些原因,强烈建议您使用最适合您的操作系统的安装方法来安装yarn。以这种速度,如果yarn宣布他们自己的注册表,允许开发人员慢慢淘汰npm,我们一点也不会感到惊讶。似乎多亏了yarn,npm终于意识到他们需要更加关注一些高要求的问题。当我审查我之前提到的高度要求的“离线”功能时,我注意到这个要求正在积极修复。pnpm如前所述,我是在pnpm的作者ZoltanKochan发表了《为什么要使用pnpm?我不会详细介绍(因为这篇文章是很久以前的事了),但您可以查看我的原始帖子了解更多信息并加入Twitter上的讨论。但我要指出的是,pnpm运行速度非常快,甚至超过了npm和yarn。为什么这么快?因为它采用了一种巧妙的方法,利用硬链接和符号链接来避免复制所有本地缓存??的源文件,这是YARN最大的性能弱点之一。使用链接并不容易,需要考虑很多问题。正如Sebastian在Twitter上指出的那样,他最初打算在yarn中使用符号链接,但由于其他一些原因而放弃了。同时,由于Github上有超过2000个Star,pnpm可以被很多人使用。此外,截至2017年3月,它继承了yarn的所有优点,包括离线模式和确定性安装。总之,我认为yarn和pnpm的开发人员做得非常出色。我个人的偏好是确定性安装,因为我喜欢控制而不喜欢惊喜。无论这场比赛的结果如何,我很感激yarn在npm脚下点燃了一把火,并提供了一个替代方案。我确信yarn是更安全的选择,但对于某些测试用例,pnpm可能是更好的选择。例如,它对于运行大量集成测试并希望尽快安装依赖项的中小型团队很有用。最后,我认为,npm仍然提供了一个非常有用的解决方案,它支持大量的测试用例。大多数开发人员仍然可以很好地使用原始的npm客户端。更多RN参考react-native技术优缺点学习ReactNative优缺点。ReactNative必看的几个开源项目,教你如何使用ReactNative。