pnpm
高性能、节省磁盘空间的 Node.js 包管理器
pnpm 通过内容寻址存储和硬链接机制消除重复依赖,安装速度比 npm 快约 3 倍,磁盘占用大幅减少。v11 引入 SQLite 索引和供应链安全增强,是 Monorepo 的最佳选择。
pnpm
高性能、节省磁盘空间的 Node.js 包管理器
技术简介说明
pnpm(performant npm)是一款面向 Node.js 生态的高性能包管理器,由 Zoltan Kochan 于 2015 年创建,2024 年后逐步过渡到社区驱动的治理模式。它在功能层面完全兼容 npm 的 package.json 生态与 registry 协议,但通过对内容寻址存储(Content-Addressable Store)、硬链接和符号链接三者的协同设计,从底层重构了依赖安装与磁盘占用的方式。
传统 npm(v2 之前)将每个项目的依赖完整拷贝到 node_modules/ 目录,同一台机器上安装十次 lodash 就会在磁盘上出现十份完全相同的副本。Yarn(Classic)通过全局缓存避免了重复下载,但安装时仍然把缓存内容拷贝到项目目录。pnpm 的做法则更进一步:所有从 registry 下载的文件会被统一存储在一个全局的内容寻址仓库(通常位于 ~/.local/share/pnpm/store/),文件名以其内容哈希命名;项目安装时,pnpm 通过硬链接将该仓库中的文件直接映射到项目的 node_modules/.pnpm/ 目录,而非拷贝。这意味着同一份 [email protected] 无论被多少项目引用,在磁盘上永远只存在一份物理数据。
在非扁平化的 node_modules 布局方面,pnpm 率先采用严格隔离策略:所有依赖被安装在 node_modules/.pnpm/ 下的一个由包名和版本号构成的虚拟存储结构中,项目真正使用的依赖通过符号链接从 .pnpm/ 目录暴露到顶层 node_modules/。这种设计杜绝了"幽灵依赖"(代码中引用了未在 package.json 中声明的包)问题,因为它使未声明的依赖在文件系统中根本不可访问。
在 monorepo 场景下,pnpm 内建工作区(Workspaces)支持,配合 pnpm-workspace.yaml 可以统一管理多个子包的依赖解析、版本协调和交叉引用。pnpm v10 引入的 Catalogs 机制进一步让 monorepo 可以在单一位置集中声明依赖版本,避免各子包之间的版本漂移。
性能层面,pnpm 官方宣称安装速度比 npm 快约 3 倍,且在冷启动和热启动场景下均保持显著优势。2026 年 4 月发布的 v11.0 将存储索引从数百万个 JSON 文件迁移到单一 SQLite 数据库,大幅提升了索引访问的 I/O 效率,特别是在包含数十万个包的仓库中,文件系统压力得到根本性缓解。
基本信息
| 属性 | 说明 |
|---|---|
| 官方网站 | https://pnpm.io/ |
| GitHub 仓库 | https://github.com/pnpm/pnpm |
| 开源许可证 | MIT License |
| 当前最新版本 | v11.10.0(2026 年 7 月) |
| 主版本演进 | v10.0(2025-01-07)→ v11.0(2026-04-28)→ v11.10.0 |
| 创始人 | Zoltan Kochan |
| 当前维护方 | pnpm 社区(Community-driven) |
| 实现语言 | TypeScript(v11 起为纯 ESM) |
| 运行要求 | Node.js ≥ 22.0.0(v11+) |
| Registry 兼容 | npm registry(registry.npmjs.org 及私有兼容服务) |
快速上手
安装
pnpm 提供三种主流安装方式,推荐根据环境选择。
方式一:独立安装脚本(推荐用于系统级安装)
# Linux / macOS
curl -fsSL https://get.pnpm.io/install.sh | sh -
# Windows (PowerShell)
Invoke-WebRequest https://get.pnpm.io/install.ps1 -UseBasicParsing | Invoke-Expression
# 安装完成后将 pnpm 加入 PATH(脚本会提示对应的 shell 配置命令)方式二:通过 npm 全局安装
npm install -g pnpm方式三:通过 Node.js Corepack(推荐用于项目级锁定)
Node.js 自 v16.9.0 起内建 Corepack,可自动管理 pnpm 版本,无需全局安装。
# 启用 Corepack
corepack enable
# 在 package.json 中声明所需 pnpm 版本
# {
# "packageManager": "[email protected]"
# }
# 之后在项目目录中执行任何 pnpm 命令,Corepack 会自动使用指定版本
pnpm install基础配置
pnpm v11 起,项目配置由 .npmrc 迁移至 pnpm-workspace.yaml。
pnpm-workspace.yaml 是 v11 的核心配置文件,承载工作区声明、依赖版本目录(Catalogs)、构建安全策略等配置:
# pnpm-workspace.yaml
# 声明 monorepo 中的工作区包路径
packages:
- 'apps/*'
- 'packages/*'
# Catalogs:集中声明依赖版本,各子包通过 catalog: 协议引用
catalog:
react: ^19.1.0
typescript: ^5.8.0
'@types/node': ^22.15.0
# 构建安全:仅允许明确列出的包运行 postinstall 等生命周期脚本
onlyBuiltDependencies:
- esbuild
- sharp
# 构建白名单(v11 合并了此前的多项构建配置)
allowBuilds:
esbuild: true
sharp: true
# 供应链保护(v11 默认开启)
minimumReleaseAge: 1440 # 单位:分钟,1440 = 1 天
blockExoticSubdeps: true.npmrc 在 v11 中仅用于与 registry 鉴权相关的配置:
# .npmrc(v11 中仅保留鉴权与 registry 地址配置)
registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
# 私有 registry 示例
@myorg:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}最小示例
# 初始化项目
mkdir my-app && cd my-app
pnpm init
# 安装依赖
pnpm add lodash
pnpm add -D typescript @types/node
# 安装指定版本
pnpm add [email protected]
# 移除依赖
pnpm remove lodash
# 执行 package.json 中的脚本
pnpm run build # 或简写为 pnpm build(pnpm 支持脚本名称直接调用)执行 pnpm install 后,生成的目录结构如下:
my-app/
├── node_modules/
│ ├── .pnpm/ # 虚拟存储:所有依赖的真实安装位置
│ │ ├── [email protected]/
│ │ │ └── node_modules/lodash/ # 硬链接指向全局 Store
│ │ └── [email protected]/
│ │ └── node_modules/typescript/
│ ├── lodash -> .pnpm/[email protected]/node_modules/lodash # 符号链接
│ └── typescript -> .pnpm/[email protected]/node_modules/typescript
├── pnpm-lock.yaml # 锁定文件
├── package.json
└── pnpm-workspace.yaml # 工作区配置(v11+)
核心概念与架构
内容寻址存储(Content-Addressable Store)
pnpm 在磁盘上维护一个全局的内容寻址仓库(Store),默认位于:
- Linux / macOS:
~/.local/share/pnpm/store/ - Windows:
%LOCALAPPDATA%\pnpm\store\
每个从 registry 下载的包文件(.tgz 解包后的实际文件)以 SHA-256 内容哈希命名后存入 Store。相同内容的文件无论来源如何,只会存储一份——这是典型的内容寻址设计,与 Git 的对象存储原理类似。
Store v11:SQLite 索引
在 v10 及更早版本中,Store 使用一个目录树结构存储索引,每个包版本对应一个 JSON 文件。当 Store 中包含数十万个包版本时,文件系统的元数据压力显著。
v11.0 引入 Store v11,将所有索引数据迁移至单一 SQLite 数据库文件(store.db)。这一变更带来以下收益:
- I/O 效率:SQLite 的 B-tree 索引结构使查找操作从 O(n) 文件系统遍历降低到 O(log n) 数据库查询
- 文件系统压力:消除了数万乃至数十万个小 JSON 文件,大幅降低 inode 消耗
- 原子性:SQLite 的写事务保证索引更新不会出现半写状态
- 并发安全:多进程同时访问 Store 时,SQLite 的锁机制提供了可靠的并发控制
硬链接(Hard Links)
Store 中的文件通过硬链接映射到 node_modules/.pnpm/ 下对应的包目录。硬链接是操作系统级别的文件系统特性,它使多个目录路径指向磁盘上同一份数据节点(inode),而不产生数据拷贝。
这意味着:
- 项目 A 和项目 B 都依赖
[email protected],磁盘上只有一份物理文件 - 删除项目 A 不会影响项目 B 对同一文件的访问(硬链接计数减一,但不删除数据)
- 安装速度接近文件系统的元数据操作速度,而非数据拷贝速度
符号链接(Symbolic Links)与 node_modules 布局
pnpm 使用符号链接构建项目实际可访问的 node_modules/ 目录:
node_modules/
├── .pnpm/ # 虚拟存储层
│ ├── [email protected]/
│ │ └── node_modules/
│ │ ├── pkgA/ # 硬链接 → Store
│ │ └── pkgB/ # pkgA 的依赖,硬链接 → Store
│ └── [email protected]/
│ └── node_modules/
│ └── pkgB/ # 硬链接 → Store
├── pkgA -> .pnpm/[email protected]/node_modules/pkgA # 符号链接
└── pkgB -> .pnpm/[email protected]/node_modules/pkgB # 符号链接
这种布局的核心价值在于:
- 幽灵依赖消除:未在
package.json中声明的包,其符号链接不会存在于顶层node_modules/,访问时直接抛出MODULE_NOT_FOUND - 版本隔离:同一包的不同版本共存于
.pnpm/下,互不干扰 - 依赖树可预测性:
node_modules/的结构严格由package.json声明决定,不受安装顺序影响
pnpm 与 npm / Yarn 的 node_modules 对比
| 特性 | npm(v3+) | Yarn(Classic) | pnpm |
|---|---|---|---|
| 依赖布局 | 扁平化(hoisting) | 扁平化(hoisting) | 严格隔离(非扁平) |
| 幽灵依赖 | 可能发生 | 可能发生 | 杜绝 |
| 磁盘复用 | 否(拷贝) | 部分(全局缓存) | 是(硬链接) |
| 循环依赖处理 | 依赖 hoisting 顺序 | 依赖 hoisting 顺序 | 天然支持(符号链接) |
核心特性
1. 极致的磁盘效率
得益于内容寻址存储与硬链接机制,pnpm 在多项目环境下的磁盘占用显著低于 npm 和 Yarn。实测数据表明,在一个包含 50 个 Node.js 项目的开发机器上,pnpm 的磁盘占用可比 npm 减少 40%~60%。在 monorepo 中,这一优势更加明显,因为多个子包共享依赖时只需一份物理数据。
2. 安装速度
pnpm 的安装速度在业界持续领先,官方基准测试显示比 npm 快约 3 倍。速度优势来源于三个方面:
- 硬链接替代数据拷贝,减少磁盘 I/O
- 并行安装多个包,充分利用 I/O 并发能力
- Store v11 的 SQLite 索引消除文件系统瓶颈
3. 严格 node_modules 隔离
pnpm 默认采用非扁平化的 node_modules 布局,从结构上杜绝幽灵依赖问题。这一设计在大型项目中尤为重要——它能捕获那些依赖了"恰好被其他包安装进来"的未声明依赖的隐性 bug。
对于确实需要访问未声明依赖的场景(通常是遗留代码迁移期),pnpm 提供 public-hoist-pattern 配置进行有限度的 hoisting:
# .npmrc 或 pnpm-workspace.yaml(v11 推荐在 pnpm-workspace.yaml 中配置)
public-hoist-pattern[]=*types*4. 原生工作区(Workspaces)支持
pnpm 内建 monorepo 工作区支持,通过 pnpm-workspace.yaml 声明包路径:
packages:
- 'apps/*'
- 'packages/*'
- 'tools/*'工作区特性包括:
pnpm --filter <package> <command>:针对特定子包执行命令pnpm -r <command>:递归对所有子包执行命令workspace:*协议:子包间引用使用本地源码而非 registry 版本- 跨子包依赖提升:共享依赖自动协调
5. Catalogs(版本目录,v10.15+)
Catalogs 允许在 monorepo 的根目录集中声明依赖版本,各子包通过 catalog: 协议引用:
# pnpm-workspace.yaml(根目录)
catalog:
react: ^19.1.0
next: ^16.0.0
typescript: ^5.8.0
catalog:
internal: # 命名 catalog
'@myorg/ui': workspace:*
'@myorg/utils': workspace:*// apps/web/package.json
{
"dependencies": {
"react": "catalog:",
"next": "catalog:",
"@myorg/ui": "catalog:internal"
}
}这一机制使版本升级只需修改根目录一处,所有子包自动同步。
6. 供应链安全
pnpm 在供应链安全方面的投入是其区别于其他包管理器的重要特征,v10 和 v11 两个大版本均以此为核心主题。
onlyBuiltDependencies(v10.0+):默认阻止所有包的 postinstall、preinstall 等生命周期脚本,仅允许白名单中的包执行。这有效防止了恶意包通过安装脚本注入代码:
# pnpm-workspace.yaml
onlyBuiltDependencies:
- esbuild
- sharp
- core-js # 明确允许的包minimumReleaseAge(v11.0 默认开启,1440 分钟):拒绝安装发布不足 1 天的包版本。这为应对恶意包抢注(typosquatting、dependency confusion 等攻击)提供了时间窗口缓冲——一旦某个包被发现存在安全问题,1 天的延迟可以让社区在恶意版本进入生产环境之前发出警报。
blockExoticSubdeps(v11.0 默认开启):阻止包含可疑特征的间接依赖,进一步收窄供应链攻击面。
strictDepBuilds(v11.0 默认开启):对所有依赖的构建行为实施严格审查。
pnpm audit --fix=update(v11.0 新增):在审计漏洞的同时,自动将受影响的依赖更新到已修复版本。
pnpm sbom(v11.0 新增):生成软件物料清单(SBOM),用于合规审查和漏洞追踪。
7. 原生发布流程(Native Publish,v11.0+)
v11 之前,pnpm publish 在底层委托给 npm CLI 完成实际的发布操作。v11 重构为完全原生实现,不再依赖 npm CLI。这消除了对 npm 版本兼容性的依赖,并使发布行为更加可预测和可控。
8. 隔离全局安装(Isolated Global Installs,v11.0+)
pnpm add -g <package> 在 v11 中会为每个全局包创建独立的隔离目录,避免全局包之间的依赖冲突。这与传统的"所有全局包共享一个 node_modules/"的模式形成对比,提高了全局工具的稳定性和可维护性。
9. pnpm ci:CI 优化命令(v11.0+)
专为持续集成环境设计的安装命令,行为特点:
- 严格遵循
pnpm-lock.yaml,存在差异时报错退出 - 跳过不必要的缓存检查,优化 CI 执行速度
- 适合替代
pnpm install --frozen-lockfile的用法
10. pnpm clean:工作区清理(v11.0+)
一键清理所有工作区包中的构建产物、node_modules 和临时文件,适合在 CI 环境或本地开发中重置工作区状态。
11. Node.js 运行时安装(v10.21+)
pnpm 支持为依赖自动安装指定版本的 Node.js 运行时,解决部分原生插件需要特定 Node.js 版本才能编译的问题,避免开发者手动切换 Node.js 版本。
12. Trust 策略配置(v10.21+)
提供显式的信任策略机制,允许开发者逐一审查并授权特定包的运行时行为,进一步收紧供应链控制粒度。
生态图
Monorepo 工具链集成
pnpm 与主流 monorepo 工具形成完整的工程化生态:
| 工具 | 与 pnpm 的关系 | 说明 |
|---|---|---|
| Turborepo | 深度集成 | pnpm Workspaces 的增量构建与任务编排;Vercel 维护 |
| Nx | 兼容支持 | 通过 @nx/js 插件支持 pnpm 作为包管理器 |
| Rush | 可选后端 | Rush 支持 pnpm 作为底层包管理器(rush init 时选择) |
| Lerna | 兼容支持 | Lerna v5+ 支持 pnpm Workspaces |
| Changesets | 原生支持 | @changesets/cli 直接读取 pnpm 工作区结构 |
Corepack 集成
Node.js Corepack(自 v16.9.0)将 pnpm 作为官方推荐的包管理器之一进行内建支持。通过在 package.json 中声明 packageManager 字段,团队成员无需手动安装 pnpm,Corepack 会自动下载并使用指定版本,消除版本不一致问题:
{
"packageManager": "[email protected]"
}编辑器与 IDE 支持
- VS Code:通过
pnpm扩展或直接使用终端集成;node_modules结构在 VS Code 的 TypeScript 语言服务中正常工作 - WebStorm / IntelliJ:内建 pnpm 支持,可在设置中选择 pnpm 作为包管理器
- Neovim:通过 LSP 和终端插件完整支持
插件生态
pnpm 通过 pnpmfile.cjs(项目级)支持安装过程钩子,可在依赖解析完成后、写入 node_modules 前修改依赖树。这在需要批量替换依赖版本或注入内部包的场景中非常有用:
// pnpmfile.cjs
function readPackage(pkg, context) {
if (pkg.name === 'some-legacy-pkg') {
pkg.dependencies['vulnerable-dep'] = '^2.0.0' // 强制替换版本
}
return pkg
}
module.exports = { hooks: { readPackage } }适用场景
大型 Monorepo
pnpm 是大型 monorepo 事实上的最佳选择。磁盘效率在多子包共享依赖时发挥到极致,工作区原语与 workspace:* 协议使子包间引用清晰且高效。配合 Turborepo 或 Nx,可以构建出高度可扩展的 monorepo 工程体系。
典型适用:
- 多个前端应用(Web、移动端、桌面端)共享组件库和工具包
- UI 库 + 设计系统 + 文档站点的多包发布
- 微前端架构下的独立子应用管理
CI/CD 流水线
pnpm 在 CI 环境中的优势体现在三方面:
- 安装速度:硬链接机制结合 Store 缓存,使
pnpm ci在热缓存场景下接近瞬时完成 - 可重现性:严格
node_modules布局 +pnpm-lock.yaml保证跨环境一致性 - CI 平台支持:GitHub Actions、GitLab CI、CircleCI 均有官方或社区提供的缓存配置示例
# GitHub Actions 示例
- uses: pnpm/action-setup@v4
with:
version: 11.10.0
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'磁盘空间受限环境
在 CI Runner 磁盘空间有限、开发机器 SSD 容量紧张、或 CI 缓存配额受限的场景下,pnpm 的磁盘效率优势最为直接。一个典型的前端项目 node_modules/ 可达数百 MB,pnpm 通过硬链接将实际新增磁盘占用降低至仅元数据级别。
安全敏感项目
pnpm v10 和 v11 的供应链安全特性使其成为对安全合规有严格要求的项目的首选:
onlyBuiltDependencies防止安装脚本攻击minimumReleaseAge提供新包发布的观察期pnpm sbom支持软件物料清单生成pnpm audit --fix=update自动修复已知漏洞
需要严格依赖隔离的项目
当项目希望彻底消除"依赖侥幸"(即代码引用了未在 package.json 中声明但恰好可用的包)时,pnpm 的严格 node_modules 布局是唯一不需要额外配置就能提供此保证的主流包管理器。
开发与工程化
开发工作流
日常开发
# 安装所有依赖
pnpm install
# 添加新依赖到根目录
pnpm add -w <package>
# 添加依赖到特定工作区子包
pnpm --filter @myorg/ui add <package>
# 运行所有子包的构建脚本
pnpm -r build
# 仅运行受变更影响的子包构建(配合 Turborepo 使用效果更佳)
pnpm --filter ...@myorg/app-web build依赖更新
# 查看所有过期依赖
pnpm outdated
# 交互式更新依赖
pnpm update --interactive
# 更新特定依赖到最新版本
pnpm update <package> --latestCI 优化策略
缓存配置
pnpm 的 Store 天然适合 CI 缓存。GitHub Actions 中推荐使用官方 action:
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
cache: 'pnpm' # 自动缓存 Store 目录对于 GitLab CI,手动配置缓存路径:
cache:
key:
files:
- pnpm-lock.yaml
paths:
- .local/share/pnpm/store/
- node_modules/增量构建
配合 Turborepo,pnpm 支持跨 CI 运行的增量构建缓存,未变更的子包可以直接从缓存恢复构建产物,跳过实际构建过程。
工作区管理最佳实践
目录结构
my-monorepo/
├── apps/
│ ├── web/ # 前端应用
│ ├── api/ # 后端服务
│ └── docs/ # 文档站
├── packages/
│ ├── ui/ # 共享 UI 组件
│ ├── utils/ # 工具函数
│ └── types/ # 共享类型定义
├── pnpm-workspace.yaml
├── pnpm-lock.yaml
├── package.json
└── turbo.json # Turborepo 配置
子包版本引用规范
// apps/web/package.json
{
"dependencies": {
"@myorg/ui": "workspace:*", // 始终使用本地源码
"react": "catalog:", // 使用 Catalog 声明的版本
"lodash": "^4.17.21" // 直接指定版本(不推荐在 monorepo 中使用)
}
}发布流程
发布单个包
# 在目标包目录下
cd packages/ui
pnpm version patch # 版本号递增
pnpm publish # 发布到 registry(v11 使用原生发布流程)批量发布(配合 Changesets)
# 记录变更
pnpm changeset
# 根据变更记录批量更新版本号并发布
pnpm changeset version
pnpm -r publish --access public性能与安全
性能基准
pnpm 的安装速度优势在多个独立基准测试中得到验证:
| 场景 | npm | Yarn Classic | Yarn Berry | pnpm |
|---|---|---|---|---|
| 干净安装(无缓存) | 基准 | ~1.2x | ~0.9x | ~2-3x |
| 热缓存安装 | 基准 | ~1.5x | ~1.1x | ~3x+ |
| 添加单个包 | 基准 | ~1.3x | ~1.0x | ~2x |
注:具体数字因项目规模、网络条件和硬件配置而异,以上为典型相对表现。
Store v11 的性能提升
Store v11 的 SQLite 索引相比 v10 的 JSON 文件索引,在以下方面有显著提升:
- 索引访问延迟:从文件系统的毫秒级目录遍历降低到 SQLite 的微秒级 B-tree 查询
- 大规模仓库:在 Store 包含超过 10 万个包版本时,索引性能提升尤为显著
- 磁盘 I/O:消除了文件系统的元数据操作开销,降低了对 SSD 寿命的消耗
供应链安全体系
pnpm 在 v10 和 v11 中构建了业界领先的供应链安全体系:
| 特性 | 版本 | 默认状态 | 说明 |
|---|---|---|---|
onlyBuiltDependencies | v10.0 | 严格模式 | 默认阻止所有包的安装脚本 |
minimumReleaseAge | v11.0 | 1440 分钟 | 拒绝安装发布不足 1 天的包 |
blockExoticSubdeps | v11.0 | true | 阻止可疑间接依赖 |
strictDepBuilds | v11.0 | true | 严格审查依赖构建行为 |
pnpm audit --fix=update | v11.0 | — | 审计并自动修复漏洞 |
pnpm sbom | v11.0 | — | 生成软件物料清单 |
| Trust 策略 | v10.21 | — | 显式信任授权机制 |
pnpm audit 与漏洞管理
# 审计所有依赖的已知漏洞
pnpm audit
# 审计并自动更新到已修复版本
pnpm audit --fix=update
# 生成 SBOM(Software Bill of Materials)
pnpm sbom --format cyclonedx > sbom.json技术对比
综合对比表
| 维度 | npm(v10+) | Yarn Berry(v4+) | Bun(v1.x) | pnpm(v11+) |
|---|---|---|---|---|
| 安装速度 | 中等 | 较快 | 最快(原生 Zig) | 快(硬链接优化) |
| 磁盘效率 | 差(完整拷贝) | 中(全局缓存) | 中 | 极佳(硬链接 Store) |
| node_modules 隔离 | 扁平化,有幽灵依赖 | 可配置 PnP / 扁平 | 扁平化 | 严格隔离,无幽灵依赖 |
| Monorepo 支持 | Workspaces(v7+) | Workspaces | Workspaces(有限) | 原生 Workspaces + Catalogs |
| 供应链安全 | 基础 audit | 基础 audit | 无 | 业界领先(多层防护) |
| Lock 文件格式 | YAML(v9+) | YAML | 二进制 | YAML |
| Offline 支持 | 有限 | 强(全局缓存) | 弱 | 强(Store + 硬链接) |
| Node.js 要求 | ≥ 18 | ≥ 18 | Bun 运行时 | ≥ 22(v11+) |
| 包管理器本身格式 | CJS/ESM | ESM | 原生二进制 | 纯 ESM(v11+) |
| 发布机制 | 原生 | 原生 | 原生 | 原生(v11+) |
| 社区生态 | 最广泛 | 较大 | 快速增长 | 较大,高质量 |
选型建议
- 首选 pnpm 的场景:Monorepo、磁盘空间敏感、安全合规要求高、需要严格依赖隔离
- 首选 Bun 的场景:追求极致安装速度、已使用 Bun 运行时、对供应链安全要求不高
- 首选 npm 的场景:简单项目、无需额外学习成本、生态兼容性优先
- 首选 Yarn Berry 的场景:已有 Yarn 历史积累、使用 PnP 模式、需要 Zero-installs
最佳实践
工作区配置建议
使用 Catalogs 集中管理版本
在 monorepo 中,始终通过 pnpm-workspace.yaml 的 Catalogs 功能集中声明共享依赖版本,避免子包间版本漂移:
# pnpm-workspace.yaml
catalog:
# 框架
react: ^19.1.0
react-dom: ^19.1.0
next: ^16.0.0
# 工具链
typescript: ^5.8.0
vite: ^7.0.0
vitest: ^3.2.0
# 类型定义
'@types/node': ^22.15.0
'@types/react': ^19.1.0使用 workspace:* 管理内部包引用
子包间引用始终使用 workspace:* 协议,确保本地开发时直接使用源码而非 registry 版本:
{
"dependencies": {
"@myorg/ui": "workspace:*",
"@myorg/utils": "workspace:*"
}
}构建安全配置
明确声明 onlyBuiltDependencies 白名单
不要使用 * 通配符绕过构建脚本限制,而应逐一审查并明确列出确实需要执行安装脚本的包:
# pnpm-workspace.yaml
onlyBuiltDependencies:
- esbuild # 需要下载平台特定二进制
- sharp # 需要编译原生插件
- core-js # 需要执行 polyfill 注入(评估后决定)保持 minimumReleaseAge 开启
默认的 1440 分钟(1 天)为合理起点,对于安全要求更高的项目可以增加到 4320 分钟(3 天):
minimumReleaseAge: 4320 # 3 天从 v10 迁移到 v11
第一步:确认 Node.js 版本
node -v # 需要 >= 22.0.0第二步:迁移配置文件
将原先在 .npmrc 中的项目配置迁移到 pnpm-workspace.yaml,.npmrc 仅保留 registry 鉴权相关配置:
# 迁移前(.npmrc 中包含项目配置)
cat .npmrc
# registry=https://registry.npmjs.org/
# strict-peer-dependencies=true
# auto-install-peers=true
# 迁移后(.npmrc 仅保留鉴权)
cat .npmrc
# registry=https://registry.npmjs.org/
# //registry.npmjs.org/:_authToken=${NPM_TOKEN}
# 迁移后(pnpm-workspace.yaml 包含项目配置)
cat pnpm-workspace.yaml
# packages:
# - 'apps/*'
# - 'packages/*'
# strictPeerDependencies: true
# autoInstallPeers: true第三步:审查构建白名单
v11 中多项构建配置合并为 allowBuilds,检查并更新配置。
第四步:删除并重新安装
# 删除旧的 node_modules 和 Store v10 索引
rm -rf node_modules
pnpm store prune
# 重新安装(自动初始化 Store v11 SQLite 索引)
pnpm installCI 环境推荐配置
# 完整 CI 示例(GitHub Actions + Turborepo + pnpm)
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 11.10.0
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm ci # 严格模式安装
- run: pnpm audit # 安全审计
- run: pnpm lint # 代码检查
- run: pnpm typecheck # 类型检查
- run: pnpm test --ci # 单元测试
- run: pnpm build # 构建(由 Turborepo 编排)技术局限与边界
纯 ESM 要求(v11+)
pnpm v11 本身为纯 ESM 实现。这意味着:
- 不能通过
require()直接加载 pnpm 的内部模块(针对 pnpm 插件开发场景) pnpmfile.cjs在 v11 中的行为需要验证,部分旧插件可能需要适配
Node.js 版本要求
v11+ 强制要求 Node.js ≥ 22.0.0。对于仍在使用 Node.js 20 LTS 的项目,需要:
- 在升级 pnpm 之前先升级 Node.js 版本
- 或使用 Corepack 锁定 pnpm v10 版本,待 Node.js 升级完成后再迁移
配置文件迁移成本
从 v10 迁移到 v11 需要将项目配置从 .npmrc 迁移至 pnpm-workspace.yaml。对于大型 monorepo,这一过程需要逐一审查和迁移配置项,存在一定的人工成本。
严格模式带来的兼容性挑战
pnpm 的严格 node_modules 隔离会暴露那些依赖幽灵依赖的遗留代码。对于从 npm 或 Yarn 迁移过来的大型项目,这可能导致大量 MODULE_NOT_FOUND 错误,需要逐一补充缺失的依赖声明。
缓解策略:
# pnpm-workspace.yaml(迁移过渡期)
# 临时允许部分 hoisting,逐步修复
public-hoist-pattern:
- '*types*' # 类型定义包通常被隐式引用
- '*eslint*' # ESLint 插件通常不显式声明Store v11 迁移
从 v10 升级到 v11 时,旧版 Store 的 JSON 文件索引不会自动迁移到 SQLite 格式。pnpm 会在首次运行时自动创建新的 SQLite 索引,但旧索引文件需要手动清理:
pnpm store prune # 清理无效条目
# 旧 JSON 索引文件可手动删除(参考官方迁移指南)与私有 Registry 的兼容性
pnpm 与标准 npm registry 协议完全兼容,但部分私有 registry 的非标准扩展(如特定平台的鉴权机制)可能存在兼容性问题,需在升级前验证。
学习资源
官方资源
- pnpm 官方文档 — 完整的功能文档与配置参考
- pnpm v11 发布博客 — v11 新特性详细说明
- pnpm v11 迁移指南 — 从 v10 迁移至 v11 的完整步骤
- GitHub 仓库 — 源码、Issue 跟踪和贡献指南
社区资源
- pnpm Discord — 官方社区讨论
- Stack Overflow
pnpm标签 — 技术问答 - 中文社区 — GitHub Discussions 中的中文讨论区
推荐学习路径
- 入门:阅读官方文档的 "Motivation" 章节,理解内容寻址存储的设计原理
- 实践:在新项目中使用
pnpm init并开始日常使用,熟悉命令和工作流 - 进阶:在 monorepo 中配置 Workspaces、Catalogs 和 Turborepo 集成
- 深入:阅读 Store v11 的 SQLite 索引设计和供应链安全机制的技术文档
- 贡献:参与 GitHub Issues 和 Discussions,帮助完善文档或修复问题
2026 年现状
版本活跃演进
pnpm v11 自 2026 年 4 月发布以来保持活跃迭代,截至 2026 年 7 月已更新至 v11.10.0。Store v11 的 SQLite 索引在实际应用中持续获得性能优化,供应链安全特性也在社区反馈下不断完善。
业界推荐地位
pnpm 在 2025~2026 年的多项前端工具链调研中被推荐为综合最佳包管理器。其优势在以下维度得到广泛认可:
- 磁盘效率:在多项目、monorepo 开发环境中的磁盘节省效果显著,成为团队选择 pnpm 的首要动因
- 安全性:v10 和 v11 的供应链安全特性使 pnpm 成为安全敏感场景的首选,也是 npm 生态中安全能力最全面的包管理器
- 速度:安装速度持续领先 npm,与 Bun 相比在具体场景下各有优势
- Monorepo 支持:原生 Workspaces + Catalogs + 严格隔离的组合,使 pnpm 在 monorepo 场景几乎没有竞品
生态整合
pnpm 与 Turborepo(Vercel 维护)的深度整合使其成为 Next.js / React 生态 monorepo 的默认推荐方案。Node.js Corepack 的持续推广也降低了团队采用 pnpm 的门槛。
供应链安全领导地位
在 2024~2025 年多起 npm 供应链攻击事件(如 ua-parser-js 被入侵、多个 typosquatting 攻击)之后,pnpm 的 minimumReleaseAge、onlyBuiltDependencies 和 blockExoticSubdeps 等特性受到更多关注。2026 年,pnpm 被多个安全合规框架(包括企业级软件供应链安全标准)列为推荐工具。
展望
pnpm 社区正在探索:
- Store v11 SQLite 索引的进一步性能优化(包括增量同步和远程 Store 支持)
- 更细粒度的供应链安全策略(如基于包来源的访问控制)
- 与 Node.js 核心团队的更紧密协作,推动包管理器标准的统一