5月28日 01:02

pnpm 的全局 store 是什么?如何管理和清理?

pnpm 之所以能在磁盘占用和安装速度上远超 npm 和 yarn,核心就在于其全局 store 机制。理解 store 的原理,不仅能帮你排查依赖问题,还能在日常开发中做出更好的决策。

全局 store 是什么

全局 store 是 pnpm 在本地维护的一个集中式依赖仓库。所有项目安装的包,其文件都只存放在 store 中一份,项目通过硬链接(hard link)引用这些文件,而非复制副本。

这意味着:10 个项目都用 lodash@4.17.21,磁盘上只占一份 lodash 的空间。

Store 的位置与结构

默认情况下,store 位于用户主目录下:

bash
# macOS / Linux ~/.local/share/pnpm/store # Windows %LOCALAPPDATA%/pnpm/store # 查看实际路径 pnpm store path

你可以通过 .npmrc 自定义 store 位置:

shell
store-dir = /path/to/custom/store

store 内部采用内容寻址存储(Content-Addressable Storage,简称 CAFS)结构:

shell
~/.local/share/pnpm/store/ ├── v3/ # store 版本号 │ └── files/ # 基于内容 hash 组织的文件 │ ├── 00/ │ │ ├── abc123... # 文件内容,以 sha256 hash 命名 │ │ └── def456... │ └── ... └── metadata.json

每个文件按其内容的 SHA-256 哈希值存储。内容相同的文件只存一份,无论它属于哪个包的哪个版本。这就是 pnpm 节省磁盘空间的根本原因。

内容寻址存储(CAFS)与三层架构

pnpm 的依赖管理采用三层架构:

  1. 全局 store(CAFS):实际文件存放处,按内容哈希索引
  2. 虚拟存储(Virtual Store):每个项目的 node_modules/.pnpm/ 目录,存放硬链接
  3. 依赖解析层node_modules 中的符号链接,形成最终的可访问结构

当执行 pnpm install 时,pnpm 先检查 store 中是否已有对应文件的哈希值。如果有,直接创建硬链接到项目的虚拟存储;如果没有,先下载到 store 再创建链接。

硬链接与 inode 的关系

硬链接是理解 pnpm store 的关键。在文件系统中,每个文件都有一个 inode(索引节点),硬链接使得多个文件路径指向同一个 inode:

shell
全局 store: ~/.local/share/pnpm/store/v3/files/00/abc123 (inode: 98765) ↓ 硬链接 项目A: project-a/node_modules/.pnpm/lodash@4.17.21/lodash.js → inode 98765 项目B: project-b/node_modules/.pnpm/lodash@4.17.21/lodash.js → inode 98765

关键特性:

  • 硬链接不占额外磁盘空间,因为它们指向同一块数据
  • 修改任一链接的文件内容,所有链接都会同步变化(所以不要手动修改 node_modules 里的文件)
  • 删除一个链接不影响其他链接,只要还有链接存在,数据就不会丢失

Store 管理:常用命令

bash
# 查看 store 路径 pnpm store path # 查看 store 状态(检查是否有损坏的包) pnpm store status # 清理未被任何项目引用的包 pnpm store prune # pnpm 9+ 可验证 store 完整性 pnpm store verify

其中 pnpm store prune 是最常用的管理命令。它会扫描 store 中所有包,检查是否还有项目通过硬链接引用它们,未被引用的包将被删除释放空间。

什么时候需要清理 store

以下场景建议执行 pnpm store prune

  • 升级 pnpm 大版本后:新版本的 store 结构可能不同,旧版本缓存可清理
  • 大量项目删除后:这些项目曾安装的包可能不再被任何项目引用
  • 磁盘空间紧张时:prune 通常能释放可观的磁盘空间
  • 依赖版本迭代后:项目升级了依赖版本,旧版本包可能不再被引用

注意:pnpm store prune 是安全操作,它只删除没有被任何项目引用的包,不会影响正在使用的依赖。

多 Store 配置

在特定场景下,你可能需要使用多个 store:

bash
# 不同分区/文件系统的项目需要独立的 store # 因为硬链接不能跨文件系统 # project-a/.npmrc store-dir = /data/store-a # project-b/.npmrc store-dir = /data/store-b

跨文件系统是使用多 store 最常见的原因。如果项目和 store 在不同磁盘分区,硬链接会失败,pnpm 会退化为复制文件,失去空间优势。

pnpm 11 的 store 变更

pnpm 11 对 store 做了重要改进:

  • SQLite 索引:用 SQLite 数据库替代了原来每个包的 JSON 索引文件,减少了系统调用,安装速度进一步提升
  • 项目追踪:通过 {storeDir}/v11/projects/ 中的符号链接注册项目,pnpm 能准确追踪哪些项目在使用哪些包,让 store prune 更加精准
  • 全局虚拟存储:全局安装的包现在有独立的隔离环境,每个 pnpm add -g 的包都有自己的目录和 lockfile

如果你在 pnpm 11 中遇到 store 相关问题,先确认 store 版本已正确迁移。

常见问题排查

安装时报硬链接错误:检查项目与 store 是否在同一文件系统。如果不是,配置 store-dir 到同一分区。

store prune 后磁盘空间没变化:可能有其他项目仍在引用这些包。用 pnpm store status 确认哪些包仍在使用。

误删了 .pnpm-store 目录:不会损坏已有项目,但下次安装依赖时需要重新下载。执行 pnpm install 即可重建。

标签:PNPM