理解pnpm及其优势

20 阅读3分钟

什么是pnpm?

pnpm (Performant NPM) 是一个快速、节省磁盘空间的JavaScript包管理工具。它采用了一种独特的依赖管理方式,通过硬链接和符号链接来共享依赖项,从而显著提高了安装速度和减少了磁盘空间占用。

pnpm与其他包管理工具的优势对比

1. 磁盘空间效率

  • npm/yarn:每个项目都会在自己的node_modules中存储依赖的完整副本,即使多个项目使用相同版本的依赖。
  • pnpm:所有依赖都存储在全局存储中,项目中的node_modules通过硬链接指向这些文件,节省大量空间。

2. 安装速度

  • npm/yarn:需要下载并解压每个包,即使已经存在于其他项目中。
  • pnpm:如果包已存在于全局存储中,只需创建硬链接,速度极快。

3. 严格的node_modules结构

  • npm/yarn:扁平化的node_modules结构可能导致依赖冲突和幻影依赖问题。
  • pnpm:使用符号链接创建严格的、可预测的node_modules结构,避免了这些问题。

4. 安全性

  • pnpm:默认情况下,只能访问在package.json中明确声明的包,提高了安全性。

5. 多包管理

  • pnpm:内置对monorepo的支持,比lerna+yarn/npm组合更高效。

软链接(符号链接) vs 硬链接

软链接(Symbolic Link)

  • 类似于Windows的快捷方式或Unix的符号链接
  • 是一个特殊的文件,包含指向另一个文件或目录的路径引用
  • 如果原始文件被删除,软链接将失效
  • 可以跨文件系统
  • 可以链接目录

硬链接(Hard Link)

  • 是原始文件的另一个名称,指向相同的inode和数据块
  • 与原始文件无法区分
  • 删除原始文件后,只要还有硬链接存在,文件数据就不会被删除
  • 不能跨文件系统
  • 不能链接目录

示例区别

文件系统结构:
/path/to/original.txt (内容: "Hello World")
/path/to/softlink.txt -> /path/to/original.txt
/path/to/hardlink.txt (与original.txt相同的inode)

操作及结果:
1. 删除original.txt:
   - cat softlink.txt → 错误: 文件不存在
   - cat hardlink.txt → 正常显示"Hello World"

2. 修改hardlink.txt内容为"Changed":
   - cat original.txt → 显示"Changed"
   - cat softlink.txt → 显示"Changed" (如果original.txt还存在)

pnpm的链接机制图解

全局存储:
~/.pnpm-store/v3/files/
  └── 00/
      └── 123456... (文件内容)

项目A:
node_modules/
  ├── .pnpm/        (虚拟存储目录)
  │   └── lodash@4.17.21/
  │       └── node_modules/lodash → 硬链接到全局存储
  └── lodash → 符号链接到 .pnpm/lodash@4.17.21/node_modules/lodash

项目B:
node_modules/
  ├── .pnpm/
  │   └── lodash@4.17.21/
  │       └── node_modules/lodash → 硬链接到同一个全局存储文件
  └── lodash → 符号链接到 .pnpm/lodash@4.17.21/node_modules/lodash

图解说明

  1. 全局存储:所有下载的包都存储在全局的pnpm存储中,内容不可变。
  2. 硬链接:每个项目的.pnpm目录中的包是全局存储中文件的硬链接,不占用额外空间。
  3. 符号链接:项目的node_modules中的包是符号链接,指向.pnpm目录中的对应包。
  4. 隔离性:每个包的依赖都在自己的node_modules中,避免了依赖冲突。

这种机制使得:

  • 同一个版本的包在磁盘上只有一份真实存储
  • 每个项目都有自己独立的依赖树视图
  • 安装速度快,因为大部分情况下只需创建链接
  • 磁盘空间使用高效,重复依赖不占用额外空间