全局虚拟存储
By default, pnpm creates a .pnpm directory inside each project's node_modules. This is the "virtual store". 它包含指向 内容寻址存储 中文件的硬链接。 Every project gets its own projection of this virtual store: pnpm hardlinks files from the content-addressable store into the .pnpm directory structure. 实际的文件内容在磁盘上只存在一次,但目录结构会为每个项目重新创建,以便 Node.js 的模块解析算法能够找到每个包的正确依赖项。
The global virtual store (virtualStoreType: global, spelled enableGlobalVirtualStore: true before v11.23.0) changes this. pnpm 不为每个项目都设置自己的 node_modules/.pnpm 目录,而是维护一个共享的虚拟存储(位于 <store-path>/links/,运行 pnpm store path 可以找到 <store-path>)。每个项目的 node_modules 目录下只包含指向这个共享位置的符号链接。
默认行为与全局虚拟存储#
默认(每个项目一个虚拟存储)#
project-a/
└── node_modules/
├── lodash → .pnpm/lodash@4.17.21/node_modules/lodash
└── .pnpm/
└── lodash@4.17.21/
└── node_modules/
└── lodash/ ← 指向内容寻址存储的硬链接
project-b/
└── node_modules/
├── lodash → .pnpm/lodash@4.17.21/node_modules/lodash
└── .pnpm/
└── lodash@4.17.21/
└── node_modules/
└── lodash/ ← 相同的硬链接,重复的目录结构
每个项目都有自己的 .pnpm 文件,其中包含硬链接。文件内容不会在磁盘上重复(硬链接共享 inode),但目录结构会重复。对于大型单体仓库或许多并行检出,在 pnpm install 期间创建数千个硬链接所花费的时间会累积。
使用全局虚拟存储#
project-a/
└── node_modules/
└── lodash → <global-store>/links/@/lodash/4.17.21/<hash>/node_modules/lodash
project-b/
└── node_modules/
└── lodash → <global-store>/links/@/lodash/4.17.21/<hash>/node_modules/lodash ← 相同目标
这两个项目都直接符号链接到全局虚拟存储中的同一位置。没有每个项目单独的 .pnpm 目录。 The global virtual store itself contains the hardlinks to the content-addressable store, but that happens only once per dependency graph (more on that below), not per project.
软件包标识如何工作#
在全局虚拟存储中,每个软件包目录都以其依赖关系图的哈希值命名。两个使用 lodash@4.17.21 且具有相同传递依赖树的项目将指向完全相同的目录。如果依赖关系树不同(例如,不同的对等依赖关系),pnpm 会创建单独的条目。这在概念上类似于 NixOS 管理软件包 使用依赖关系图哈希的方式。
何时使用它#
The global virtual store is most useful when you have multiple checkouts of the same project on disk. For example, when using git worktrees for multi-agent development. 在这种情况下,每个工作树都可以获得几乎无成本的 node_modules,因为所有真正的包内容都已存在于共享存储中。
它还可以加快同一台机器上不相关项目的安装速度,因为任何项目已经安装的任何软件包版本都可以立即使用。
局限性#
- CI 环境:在 CI 中,通常没有缓存,因此没有可用的全局热存储。全局虚拟存储在 CI 中通常没用。
- 共享信任域:全局虚拟存储和内容寻址存储属于共享可写状态。仅将其用于相互信任的项目、用户和作业,并利用文件系统权限保护存储路径。
- ESM hoisting: pnpm uses the
NODE_PATHenvironment variable to support hoisted dependencies with the global virtual store, and Node.js does not respectNODE_PATHfor ESM imports. Since v11.23.0, every process pnpm spawns for the project (pnpm run,pnpm exec, lifecycle scripts, and the toolspnpm dlxruns) also gets aNODE_OPTIONS--importflag registering a resolve hook that restores those lookups, so a dependency importing a package it does not declare resolves under ESM too (#9618). Anodeprocess started outside pnpm does not get that environment, and settingextendNodePathtofalseturns the wholeNODE_PATHmechanism off, resolve hook included; declare the missing dependencies with packageExtensions if you need them to resolve in either case.
注意
全局虚拟存储目前对于项目安装默认处于禁用状态,并被标记为实验性功能,因为某些工具可能无法正确处理符号链接的 node_modules。 You need to explicitly set virtualStoreType: global in pnpm-workspace.yaml to use it for project installs. 在 pnpm v11 中,默认情况下,通过 pnpm dlx (pnpx) 安装的软件包和全局安装的软件包都会启用全局虚拟存储。目标是在未来的版本中默认启用该功能。
全局软件包#
在 pnpm v11 中,全局安装(pnpm add -g)和 pnpm dlx 默认使用全局虚拟存储。有关 v11 中全局软件包管理如何工作的完整指南,包括隔离安装和新的二进制文件位置,请参阅 全局软件包。
配置#
See the virtualStoreType setting reference for all configuration details. virtualStoreType was added in v11.23.0 as the canonical spelling of enableGlobalVirtualStore, which keeps working.