核心定位

pnpm(Performant npm)是 Node.js 生态的包管理器,重点是速度、磁盘效率、严格依赖隔离、可复现安装和 monorepo 支持。它不是 npm 的兼容外壳,而是使用不同的依赖存储与 node_modules 链接模型。

截至 2026-08-20,稳定版为 pnpm 11.22.0。官方仓库同时包含 TypeScript CLI 和 Rust 实现;Rust 实现官方称为 pacquet,当前仍标注为“尚未适合生产环境”。

pnpm 的主要优点

1. 内容寻址存储节省磁盘空间

pnpm 把包文件存入全局的内容寻址存储(Content-Addressable Storage, CAS)。不同项目依赖同一版本时,项目的 node_modules 不会各自保存完整副本,而是通过 hard link 或 reflink 引用存储中的文件。

因此:

  • 多个项目共享同一依赖文件;
  • 同一包的不同版本只保存差异文件;
  • 清理项目目录不会影响其他项目使用的包;
  • 大型 Node.js 开发环境通常能明显减少磁盘占用。

2. 严格依赖访问

pnpm 默认使用非扁平化的依赖布局。包只能访问自己 package.json 中声明的依赖,不能像传统扁平 node_modules 那样偶然访问某个依赖的传递依赖。

这能较早暴露:

  • 漏写直接依赖;
  • 依赖声明不完整;
  • 依赖升级后因“幽灵依赖”(phantom dependency)导致的隐藏兼容问题。

必要时可通过配置 nodeLinker: hoisted 兼容一些依赖扁平目录的旧工具,但这会牺牲一部分隔离性。

3. 安装和 CI 通常更快

依赖包已存在全局存储时,pnpm 主要执行链接而非重复复制。官方 README 声称在部分基准中最高可达到 npm 和 Yarn Classic 的约两倍速度;实际结果取决于缓存命中率、文件系统、网络和依赖结构。

CI 中通常配合:

pnpm install --frozen-lockfile

它会依据提交的 pnpm-lock.yaml 安装,不允许清单与锁文件不一致时悄悄改锁文件。

4. monorepo / workspace 支持好

pnpm 原生支持 workspace,可以在一个仓库中管理多个包,并提供:

  • workspace 内部包链接;
  • workspace: 协议;
  • 递归执行脚本;
  • filter 选择性安装、构建和测试;
  • catalog 统一维护依赖版本;
  • deploy 生成相对独立的部署目录。

例如:

pnpm --filter web dev
pnpm --filter './packages/*' test
pnpm -r build

5. 可复现性和工程约束

pnpm 使用 pnpm-lock.yaml,并支持在 package.json 中声明:

{
  "packageManager": "pnpm@11.22.0"
}

团队可以进一步使用 Corepack、mise、Volta 或 CI 检查来固定 pnpm 版本,避免不同版本生成不同锁文件或产生行为差异。

与 npm 的主要差异

方面npmpnpm
存储项目通常各自复制包全局 CAS + link/reflink
目录布局默认较扁平默认隔离,.pnpm 虚拟存储
依赖约束更容易意外访问传递依赖默认只能访问声明的直接依赖
monorepoworkspaces 可用workspace/filter 能力更强、更成熟地融入 CLI
迁移成本零通常低,但某些依赖假设扁平 node_modules 时需要调整
团队学习成本较低需要理解 store、workspace、filter 和链接布局

pnpm 命令大多接近 npm:pnpm add、pnpm remove、pnpm run、pnpm exec、pnpm dlx,所以入门迁移成本不高。

Rust 重写的实际状态

Rust 实现不是完全不同的包管理器,而是 pnpm 的另一套实现,目标是保持相同的命令、参数、默认值、错误码、文件格式和目录布局。

官方路线分两阶段:

  1. Phase 1:fetching and linking。先让 Rust 实现接管包下载与链接,TypeScript CLI 继续负责锁文件和其他逻辑;官方预期仅这一阶段就能在多数场景中显著提速。
  2. Phase 2:resolution。再逐步由 Rust 接管依赖解析。

截至 2026-08-20:

  • pnpm 稳定版是 11.22.0;
  • pnpm 12 仍为 12.0.0-rc.7 预发布版本;
  • pnpr / pacquet 仍处于 alpha/实验阶段;
  • 官方 pacquet README 明确写着尚未适合生产环境;
  • GitHub 上仍有 Rust CLI 解析 .modules.yaml、配置项兼容和 CLI 行为方面的开放问题。

因此,不能把“pnpm 新版”简单理解成“已经全面 Rust 化且更稳定”。更准确的说法是:pnpm 的成熟产品正在逐步把性能关键路径迁移到 Rust,同时保留行为兼容目标。

建议的试用策略

稳妥方案:先试稳定 pnpm 11

适合日常项目:

corepack enable
corepack prepare pnpm@11.22.0 --activate
pnpm --version

如果 Node.js 环境不使用 Corepack,也可以使用官方安装方式或将 pnpm 固定在项目的 packageManager 字段中。已有项目第一次迁移前应提交当前 lockfile,并在独立分支执行:

pnpm import                 # 从 package-lock.json 或 yarn.lock 导入时使用
pnpm install
pnpm install --frozen-lockfile
pnpm test
pnpm build

不建议在同一个项目中反复交替使用 npm、Yarn 和 pnpm 修改依赖清单;应选定一个包管理器并提交对应锁文件。

冒险方案:单独测试 pnpm 12 RC / Rust CLI

仅建议用于临时复制项目、基准测试和反馈问题:

  • 不要在生产 CI 中作为唯一安装路径;
  • 不要让 RC 重写主分支锁文件后直接提交;
  • 重点测试 peer dependencies、原生模块、monorepo、Windows 文件链接、pnpm deploy 和自定义 registry;
  • 若结果异常,回退到稳定版并用 pnpm-lock.yaml 对比结果。

Windows 上的注意事项

pnpm 的链接模型依赖文件系统行为。Windows 上遇到权限、杀毒软件占用文件、跨盘符链接或 store 路径问题时,常见处理方向是:

  • 让 store 与项目位于合适的磁盘/文件系统;
  • 避免用管理员权限和普通权限混用生成同一个项目;
  • 检查 Git、杀毒软件和编辑器是否锁住 node_modules;
  • 用 pnpm store path 查看 store 位置;
  • 用 pnpm config get store-dir 查看当前配置。

一句话结论

如果想体验:现在就用稳定版 pnpm 11,它已经足够成熟,主要收益是磁盘占用、依赖隔离和 monorepo 体验;如果想体验 Rust 重写,则把 pnpm 12 RC/pacquet 当作实验性性能预览,先在复制项目和非关键 CI 中验证,不要把它当作生产默认值。

参考


本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/nodejs