npm、yarn、pnpm的区别

408 阅读10分钟

1. 介绍及发展历史

以下是npmyarnpnpm包管理工具的介绍:

  • npmnpm是最早的Node.js包管理工具,由Isaac Z. Schlueter于2010年创建。它是Node.js社区默认的包管理工具,也是最流行的工具之一。它具有简单易用、灵活、生态系统完备等优点,在社区得到了广泛认可和使用。
  • yarnyarn是由Facebook于2016年发布的另一款Node.js包管理工具,旨在提高npm的安装速度和可靠性。yarn具有离线安装、并行下载、版本锁定、优先使用本地缓存等特性,已成为许多开发者的选择。
  • pnpmpnpm是最近的Node.js包管理工具之一,它在2016年由Zoltán Kochan开发。pnpm的设计思想是使用符号链接和递归锁定来优化依赖项管理,从而提高安装速度和减少磁盘空间占用。近年来,pnpm在开源社区中逐渐得到认可,并且已经被许多公司和组织所使用。

总之,随着Node.js生态系统的不断壮大,像npmyarnpnpm这样的包管理工具的出现,使得Node.js开发者可以更有效地管理和分享代码库,提高项目的开发效率。

npm文档
yarn文档
pnpm文档

2. 更新历史

2.1 npm的一些重要更新历史和变化:

  • npm 1.0.0: 该版本是npm的第一个稳定版本,标志着npmNode.js独立出来,成为了一个独立的包管理器。该版本引入了npm shrinkwrap命令,用于创建和维护项目的依赖关系树。
  • npm 2.0.0: 该版本引入了scoped packages,允许使用者将包命名为@namespace/package-name的形式,以避免包名称冲突。该版本还引入了自动压缩,使安装包时的下载和解压时间减少。
  • npm 3.0.0: 该版本引入了扁平化依赖关系树,使依赖项更容易管理和理解。此版本也使 npmyarn等新的竞争对手相比,更好地解决了依赖项的解析问题。
  • npm 5.0.0: 该版本引入了npm ci命令,可以用于快速、干净、准确地安装项目的依赖关系。此版本还引入了本地缓存,以避免在网络上下载相同的依赖项。
  • npm 7.0.0: 该版本引入了与Node.js 15捆绑在一起,引入了许多新特性,包括Workspaces、自动垃圾回收、改进的CLI和搭配安装。Workspaces是一个大型项目管理工具,可以同时管理多个包并在它们之间共享依赖项。

node对于npm的版本

image.png

除了这些重要的版本历史和变化之外,npm还对性能、安全、易用性和用户体验等方面进行了许多改进

2.2 Yarn 的一些重要更新历史:

  • Yarn 0.16.0: 这是 Yarn 的第一个公共版本,发布于 2016 年。它引入了 Yarn 的锁定文件机制,以解决因不同依赖版本之间的冲突而导致的一些问题。此外,它还提供了各种命令来管理依赖项,比如 yarn add、yarn remove 和 yarn upgrade 。
  • Yarn 1.0.0: Yarn 1.0.0 发布于 2017 年,其中包含了一些新特性和改进,如安装顺序的优化、自适应网络速度的下载速度控制和完全离线的安装等。
  • Yarn 2.0.0: Yarn 2.0.0 发布于 2020 年,其中最大的变化是默认使用 PnP (plug-n-play) 解决方案,这是一种新的依赖项解决方案,将依赖项放在项目的虚拟文件系统中,以提高速度和可靠性。此外,它还包括其他一些新功能,例如交互式提示符和基于 node-modules 的缓存目录结构。
  • Yarn 3.0.0: Yarn 3.0.0 pre-release 发布于 2021 年,它引入了一些重要的变化。最重要的是它摆脱了之前几个版本中使用的 PnP 方案,改为使用 Zero-Installs 方案,以进一步优化依赖项安装和管理。此外,它还提供了单独运行 Yarn 命令的能力并增强了缓存管理。

除了这些版本之外,Yarn 还对其用户界面和其他属性进行了很多改进,以便更好地管理现代化的 JavaScript 项目依赖性。

2.3 pnpm 的一些重要更新历史:

  • pnpm 1.0.0: 这是 pnpm 的第一个正式版本,发布于 2016 年。它引入了 pnpm 的唯一依赖解决方案,该方案能够解决依赖项大小的问题,以及使用硬链接和符号链接来节省空间。
  • pnpm 2.0.0: pnpm 2.0.0 发布于 2017 年,其中包含了一些新特性和改进,如安装顺序优化和改进的缓存机制等。
  • pnpm 3.0.0: pnpm 3.0.0 发布于 2018 年,其中最大的变化是引入了工作区安装 (workspaces),允许您在一个代码库中管理多个相关项目的依赖关系。此外,它还包括其他一些新功能,例如可选的锁版本选项和增强的缓存机制。
  • pnpm 4.0.0: pnpm 4.0.0 发布于 2019 年,引入了一些新特性和改进,例如并行安装和增强的配置选项。
  • pnpm 5.0.0: pnpm 5.0.0 发布于 2020 年,其中最大的变化是切换到了 ES Modules,并且采用了全新的 pnpm 子命令系统来提高性能和用户体验。此外,它还包括其他一些新功能,例如增强的依赖分析和工作区安装的功能增强。
  • pnpm 6.0.0: pnpm 6.0.0 发布于 2021 年,引入了一些新特性,包括并发下载、改进的锁版本算法、对 Windows 文件系统的改进支持等。

上述更新只是 pnpm 的一部分,它们展示了 pnpm 不断演进和创新的过程,力求提供更好的体验和效果。

3. 具体使用情况

3.1 npm2使用

为了了解npm之前安装依赖的情况,先使用n进行切换版本,node版本切换后npm版本会随之变化,先使用npm2版本进行尝试.

用 node 版本管理工具把 node 版本降到 4 使用n 4,那 npm 版本就是 2.x 了。

image.png

  1. 初始化项目npm init -y
  2. 安装npm i koa -S
  3. 查看包安装情况

同一个依赖depd重复安装

image.png

嵌套层级过深,每个依赖都有自己的 node_modules

image.png

大小

image.png

上面会产生几个问题:

  1. 公共的依赖不能复用
  2. windows 的文件路径最长是 260 多个字符,这样嵌套是会超过 windows 路径的长度限制的
  3. 同样的依赖会复制很多次,会占据比较大的磁盘空间

为了解决上述问题,出来新的解决方案了,就是 yarn

3.2 yarn、npm8 使用

  1. 将版本提升否则yarn初始化失败
  2. 初始化项目yarn init -y
  3. 安装依赖 yarn add koa

yarn 是怎么解决依赖重复很多次,嵌套路径过长的问题的呢?

铺平。所有的依赖不再一层层嵌套了,而是全部在同一层,这样也就没有依赖重复多次的问题了,也就没有路径过长的问题了。

image.png

为什么还有嵌套呢?

因为一个包是可能有多个版本的,提升只能提升一个,所以后面再遇到相同包的不同版本,依然还是用嵌套的方式。

大小:

image.png

npm8

npm 后来升级到 3 之后,也是采用这种铺平的方案了,和 yarn 很类似:

image.png

image.png

上述方式没有缺陷吗?

  1. 幽灵依赖

最主要的一个问题是幽灵依赖,也就是你明明没有声明在 dependencies 里的依赖,但在代码里却可以 require 进来。

这个也很容易理解,因为都铺平了嘛,那依赖的依赖也是可以找到的。

但是这样是有隐患的,因为没有显式依赖,万一有一天别的包不依赖这个包了,那你的代码也就不能跑了,因为你依赖这个包,但是现在不会被安装了。

这就是幽灵依赖的问题。

  1. 磁盘空间浪费

就是上面提到的依赖包有多个版本的时候,只会提升一个,那其余版本的包不还是复制了很多次么,依然有浪费磁盘空间的问题。

那社区有没有解决这俩问题的思路呢?

pnpm 就出来了

3.3 pnpm使用

npm3 和 yarn 为什么要做 node_modules 扁平化?不就是因为同样的依赖会复制多次,并且路径过长在 windows 下有问题?

那如果不复制,比如通过link的方式解决磁盘空间问题。

前置知识:

软硬链接:

软链接(软连接):是一个指向另一个文件的路径的特殊文件。软链接是对实际文件的引用,它不包含实际内容,而是只包含指向实际文件的地址。当目标文件被删除后,软链接将不再有效。可以创建不同文件系统之间的软链接,实现跨文件系统的链接。

硬链接(硬连接):是指与一个文件关联的两个或多个目录条目。硬链接只有在与原始文件在同一个文件系统上时才有效。硬链接的创建方式是复制索引节点,因此,硬链接与原始文件有相同的属性。硬链接本身不包含源文件的路径,只有对应的索引节点信息。删除源文件不影响硬链接,因为硬链接不依赖于源文件的路径。硬链接实际上允许一个文件在不同目录中具有不同的文件名。

在 pnpm 中,软链接和硬链接的使用取决于包管理策略。通常情况下,pnpm 通过软链接的方式将依赖关系连接到项目。

mac中创建软硬链接: 在 macOS 系统中,可以通过命令行使用 ln 命令来创建软链接和硬链接。

创建软链接(符号链接):

ln -s <源文件或目录> <链接文件或目录>

例如,创建一个名为 prettier-ln 的软链接,指向名为 prettier 的源文件,命令如下:

ln -s sourceCode/prettier prettier-ln // 目录
ln -s sourceCode/prettier/package.json pkg-ln.json // 文件

创建软链接解决重复安装依赖磁盘空间问题 image.png

创建硬链接:

ln <源文件> <链接文件>

例如,创建一个名为 prettier-hard 的硬链接,指向名为 prettier 的源文件,命令如下:

ln -s sourceCode/prettier prettier-hard // 目录
ln -s sourceCode/prettier/package.json pkg-hard.json // 文件

修改硬链接的内容,会影响原文件,删除也不会影响原文件。 image.png

image.png

请注意,硬链接不能用于目录,也不能跨越不同的文件系统。在这些情况下,请使用软链接。


  1. 初始化项目 pnpm init
  2. 安装依赖pnpm add koa

image.png 包是从全局 store 硬连接到虚拟 store 的,这里的虚拟 store 就是 node_modules/.pnpm。

image.png

只在全局仓库保存一份 npm 包的内容,其余的地方都 link 过去,.npm使用硬链接这样不会有复制多次的磁盘空间浪费,而且也不会有路径过长的问题。因为路径过长的限制本质上是不能有太深的目录层级,现在都是各个位置的目录的 link,并不是同一个目录,所以也不会有长度限制。

image.png

image.png

大小:

image.png

结合图理解

image.png

解决了npm、yarn的问题