本篇文章带大家了解一下三种JavaScript包管理器(npm、yarn、pnpm),并将这三种包管理器进行对比,聊聊npm、yarn、pnpm三者的区别和关联,希望对大家有所帮助,如有问题欢迎指出!
包管理器领域的三个主要参与者:
-
npm
-
Yarn
-
高性能 npm (pnpm)
实际上我们已经在所有包管理器中实现了基本相似的功能,因此您很可能会根据非功能性要求来决定使用哪个包管理器,例如安装速度、存储消耗或实际情况。
当然,您选择使用每个包管理器的方式会有所不同,但它们都有基本一致的概念。以上这些包管理器都可以执行以下指令:
- 读写数据
- 批量安装或更新所有依赖项
- 添加、更新和删除依赖项
- 运行脚本
- 发布包
然而尽管如此,包管理器在底层还是有所不同的。传统上 npm
和 Yarn
将依赖项安装在一个平铺的node_modules文件夹中。(这里注意先后顺序,是 yarn
先平铺的,之前 npm
是递归)。但是平铺也会造成一系列的安全问题。
依赖结构的不确定性。
扁平化算法本身的复杂性很高,耗时较长。
项目中仍然可以非法访问
有声明过依赖的包
因此,pnpm
在 node_modules
文件夹中引入了一些新概念来更高效的存储依赖,。Yarn Berry
甚至通过完全放弃 node_modules
的 (PnP) 模式(另一个文章会具体说明)来走得更远。
JavaScript package简史
最早发布的包管理器是 npm
,早在 2010 年 1 月。它就确立了今天包管理器工作的核心原则。但是既然 npm
已经存在 10 多年了,为什么还有其他选择?以下是出现这种情况的一些关键原因:
node_modules
文件夹结构的依赖关系解析算法不同(嵌套 & 平铺、node_modules
vs. PnP mode)- 依赖提升方式不同(
hoisting
) locking
格式不同(性能都不同,比如yarn
自己写的那一套)- 磁盘存储包文件方式不同(空间效率不同)
- 多包项目(又名
workspaces
)的支持不同,这会影响monorepos
的可维护性和速度 - 新工具和命令的需求不同(通过插件和社区工具对可扩展性的需求不同)
- 可配置性和灵活性不同
让我们深入了解一下 npm
崛起后这些方面如何确定的历史,Yarn Classic
如何解决其中的一些问题,pnpm
如何扩展这些概念,以及 Yarn Berry
作为 Yarn Classic
的继任者如何打破这些传统的概念和流程。
先驱者 npm
npm
是包管理器的鼻祖。许多人错误地认为 npm
是“Node package manager”的首字母缩写词,但事实并非如此。
它的发布构成了一场革命,因为在此之前,项目依赖项都是手动下载和管理的。npm
引入了诸如文件及其元数据字段、将依赖项存储在node_modules
, 自定义脚本, 公共和私有包等等。
2020 年,GitHub 收购了 npm,所以原则上 npm
现在归微软管理。在撰写本文时,最新的主要版本是 v8,于 2021 年 10 月发布。
创新者 Yarn Classic
在 2016 年 10 月,Facebook 宣布与 Google 和其他一些公司合作开发一个新的包管理器(engineering.fb.com/2016/10/11/…),以解决 npm 当时存在的一致性、安全性和性能问题。他们将替代品命名为Yarn。
尽管 Yarn
还是基于 npm
的许多概念和流程来架构设计的,但 Yarn
还是对包管理器领域产生了重大影响。与 npm
相比,Yarn
并行化操作以加快安装过程,这一直是 npm
早期版本的主要痛点。
Yarn
为读写、安全性和性能设定了更高的标准,还发明了许多概念(后来npm
也为此做了很多改进),包括:
monorepo
支持- 缓存安装
- 离线下载
- 文件锁(
Locking
)
Yarn v1 于 2020 年进入维护模式 。从那时起,v1.x 系列被认为是旧版,并更名为 Yarn Classic
。它的继任者 Yarn v2 (Berry) 现在是更加活跃的开发分支。
更高效的pnpm
pnpm
的第 1 版由 Zoltan Kochan于 2017 年发布。它是 npm
的替代品,所以如果你有一个 npm
项目,你可以马上使用 pnpm
!
创建 pnpm
的主要原因是 npm
和 Yarn
对于跨项目使用的依赖项存储结构非常冗余。尽管 Yarn Classic
比 npm
具有速度优势,但它使用相同的依赖解析方法,这对 pnpm
来说是不行的:npm
和 Yarn Classic
使用 hoisting
来平铺他们的 node_modules
.
pnpm
没有优化之前的结构,而是引入了另一种依赖解决策略:内容寻址的一种存储结构。此方法生成的 node_modules
文件夹其实是依赖于全局存储在主文件夹上的 ~/.pnpm-store/
目录。每个版本的依赖项都物理形式存储在该目录文件夹中一次,构成单一的源地址来节省相当多的磁盘空间。
node_modules
结构是通过使用 symlinks
创建依赖关系的嵌套结构(其中文件夹内每个文件/包都是通过硬链接存储)官方文档中的下图阐明了这一点。(待填坑:软硬链接)
2021 年报告中可见 pnpm
的影响力:因为他们在内容可寻址存储方面的创新,竞争对手都希望采用 pnpm
的概念,比如象征性链接的结构和包的高效磁盘管理。
Yarn (v2, Berry),用 Plug'n'Play 重新发明的轮子
Yarn 2于 2020 年 1 月发布,被宣传为原始 Yarn
的重大升级。Yarn
团队将其称为 Yarn Berry
以更明显地表明它本质上是一个具有新的代码库和新的原则规范的新包管理器。
Yarn Berry
的主要创新是其即插即用 (PnP)方法,它是作为修复node_modules的策略。不是生成node_modules
的策略,而是生成一个带有依赖查找表的文件 .pnp.cjs
,因为它是单个文件而不是嵌套的文件夹结构,所以可以更有效地处理依赖。此外,每个包都以zip 文件的形式存储在文件夹内来替代 .yarn/cache/
,占用的磁盘空间也比 node_modules
少。
所有这些变化如此之快以至于在发布后引起了很大的争议。PnP 这种破坏性的重大更改要求维护者更新他们现有的包以便与其兼容。默认情况下使用全新的 PnP 方法并且恢复到 node_modules
最初并不简单,这导致许多知名开发人员没有加入其中的考虑且公开批评 Yarn 2。
此后,Yarn Berry
团队在其后续版本中解决了许多问题。为了解决 PnP 的不兼容问题,团队提供了方法来轻松更改默认操作模式。在node_modules插件的帮助下,切换回传统 node_modules
方法只需要一行配置。
此外,随着时间的推移,JavaScript 生态系统为 PnP 提供了越来越多的支持,正如您在此兼容性表中所见,一些大型项目已经开始采用 Yarn Berry
。
尽管 Yarn Berry
还很年轻,但它也已经对包管理器领域产生了影响——pnpm
在 2020 年末采用了PnP 方法。
安装工作流程
首先必须在每个开发人员的本地和 CI/CD 系统上安装包管理器。
npm
npm
与 Node.js
一起提供,因此不需要额外的步骤。除了为您的操作系统下载Node.js 安装程序外,使用 CLI 工具管理软件版本已成为一种常见做法。在 Node 的上下文中,Node Version Manager (nvm) 或 Volta 已成为非常方便的实用程序。
Yarn Classic 和 Yarn Berry
您可以通过不同的方式安装 Yarn 1,例如,作为 npm
包来安装:.$ npm i -g yarn
要从Yarn Classic 迁移到 Yarn Berry,推荐的方法是:
-
安装或更新
Yarn Classic
到最新的版本 -
使用命令升级到最新的现代版本
yarn set version berry
但是,在此推荐的安装 Yarn Berry方法是通过 Corepack。
Corepack是由 Yarn Berry 的开发者创建的。该计划最初被命名为包管理器管理器(pmm) ?,并在 LTS v16 中与 Node 合并。
在 Corepack 的帮助下,因为 Node 包含 Yarn Classic
、Yarn Berry
和 pnpm
二进制文件所以您不必“单独”安装的 npm
的替代包管理器。这些垫片允许用户运行 Yarn 和 pnpm 命令而无需先显式安装它们,也不会弄乱 Node 发行版。
Corepack 预装了 Node.js ≥ v16.9.0。但是,对于较旧的 Node 版本,您可以使用⬇️
npm install -g corepack
在使用之前先启用 Corepack。该示例显示了如何在 Yarn Berry v3.1.1 中激活它。
# you need to opt-in first $ corepack enable # shim installed but concrete version needs to activated $ corepack prepare yarn@3.1.1 --activate
pnpm
您可以将 pnpm
作为 npm
包来安装: $ npm i -g pnpm
。您还可以使用 Corepack 安装 pnpm :
$ corepack prepare pnpm@6.24.2 --activate
项目结构
在本节中,您将一目了然地看到不同包管理器的主要特征。您可以轻松发现配置特定包管理器涉及哪些文件,以及哪些文件是由安装步骤生成的。
所有包管理器都将所有重要的元信息存储在项目清单package.json文件中。 此外,根级别的配置文件可以被用来设置不同的私有包或者不同的依赖项解析配置。
在安装步骤中,依赖项 dependencies
被存储在文件结构中,例如 node_modules
并生成锁定文件 locking
。本节不考虑工作区设置,因此所有示例仅显示存储依赖项的单个位置。
npm
使用$ npm install
或较短的 $ npm i
会生成一个 package-lock.json
文件和一个 node_modules
文件夹。还有 .npmrc
这种可配置的文件可以放在根级别目录里面。有关 locking
文件的