pnpm
pnpm(Performant npm)是高效的 Node.js 包管理器,通过内容寻址存储 + 硬链接避免重复安装相同依赖,显著节省磁盘空间并加快安装速度。同时采用严格的依赖隔离,消除「幽灵依赖」问题。
同类工具:npm(官方默认)、yarn(lockfile 稳定)。
安装
# 推荐:通过 npm 全局安装
npm install -g pnpm
# 或通过独立安装脚本(不依赖现有 Node/npm)
curl -fsSL https://get.pnpm.io/install.sh | sh -
# 升级 pnpm 自身
pnpm self-update
# 验证
pnpm --version核心原理
内容寻址存储(CAS)
所有下载的包存储在全局 store(~/.pnpm-store),按包内容的哈希值索引。同一个包的同一版本在磁盘上只存一份,项目的 node_modules 通过硬链接指向 store:
~/.pnpm-store/ ← 全局缓存(内容寻址)
v3/
files/
00/abc123... ← 文件按哈希存储
project-a/node_modules/ ← 硬链接,指向 store
project-b/node_modules/ ← 同一份文件,无重复占用
严格依赖隔离
npm / yarn 的 node_modules 扁平化结构允许代码访问未在 package.json 中声明的包(幽灵依赖)。pnpm 采用符号链接结构,只有显式声明的依赖可被访问:
node_modules/
├── .pnpm/ ← 实际包文件(隔离)
│ ├── express@4.18.2/
│ └── lodash@4.17.21/
├── express -> .pnpm/express@4.18.2/node_modules/express
└── lodash → .pnpm/lodash@4.17.21/node_modules/lodash
基本命令
# 安装所有依赖
pnpm install
pnpm i # 缩写
# 安装生产依赖
pnpm add express
pnpm add express@4.18.2 # 指定版本
# 安装开发依赖
pnpm add -D typescript jest
pnpm add --save-dev eslint
# 安装全局工具
pnpm add -g nodemon
pnpm add -g typescript
# 卸载
pnpm remove express
pnpm remove -D jest
# 更新依赖
pnpm update # 更新所有(在版本范围内)
pnpm update express # 更新指定包
pnpm update --latest # 忽略版本范围,升级到最新运行脚本
pnpm run dev
pnpm run build
pnpm run test
pnpm test # test / start / install 可省略 run
pnpm start
# 传递额外参数
pnpm run test -- --coveragepnpm-lock.yaml
pnpm 使用 pnpm-lock.yaml 作为锁文件(类似 package-lock.json),必须提交到 Git,确保团队和 CI 安装结果一致。
# CI 环境:严格按锁文件安装,不更新
pnpm install --frozen-lockfile
# 验证 lockfile 是否与 package.json 同步
pnpm install --frozen-lockfile --check-if-lockfile-emptyMonorepo(工作区)
pnpm 内置 workspace 支持,是 Monorepo 的主流选择(Turborepo、Nx 均推荐 pnpm):
配置
根目录创建 pnpm-workspace.yaml:
packages:
- 'packages/*'
- 'apps/*'
- '!**/__tests__/**' # 排除测试目录项目结构示例:
monorepo/
├── pnpm-workspace.yaml
├── package.json # 根 package(通常不发布)
├── packages/
│ ├── ui/ # 共享组件库
│ │ └── package.json # name: "@myorg/ui"
│ └── utils/ # 工具函数
│ └── package.json # name: "@myorg/utils"
└── apps/
├── web/ # 前端应用
└── api/ # 后端服务
工作区命令
# 在所有包中执行命令
pnpm -r run build # --recursive 的缩写
# 在指定包中执行
pnpm --filter @myorg/ui run build
pnpm --filter web run dev
# 按拓扑顺序构建(先构建被依赖的包)
pnpm -r --sort run build
# 工作区内包互相引用(使用 workspace: 协议)
# apps/web/package.json
{
"dependencies": {
"@myorg/ui": "workspace:*" # 指向本地包
}
}工作区安装:
# 在根目录安装所有 workspace 的依赖
pnpm install
# 只给某个包添加依赖
pnpm add lodash --filter @myorg/utils.npmrc 配置
pnpm 复用 .npmrc 格式,支持额外配置项:
# 镜像源
registry=https://registry.npmmirror.com
# 全局 store 路径(可自定义)
store-dir=~/.pnpm-store
# 提升特定包到根 node_modules(兼容某些工具的路径假设)
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
# 严格模式:禁止访问未声明的依赖(默认已严格,此项用于调试)
strict-peer-dependencies=false
# 自动安装 peerDependencies(pnpm 8+ 默认 true)
auto-install-peers=true全局 store 管理
# 查看 store 路径
pnpm store path
# 清理孤立包(无任何项目引用的缓存)
pnpm store prune
# 验证 store 完整性
pnpm store verifypnpm vs npm vs yarn 对比
| 特性 | npm | yarn | pnpm |
|---|---|---|---|
| 安装速度 | 中 | 快 | 最快 |
| 磁盘占用 | 最高 | 高 | 最低 |
| 幽灵依赖 | 存在 | 存在 | 严格隔离 |
| Monorepo | 基础支持 | Workspaces | 原生优秀支持 |
| 锁文件 | package-lock.json | yarn.lock | pnpm-lock.yaml |
| 生态兼容 | 最广 | 广 | 广(少数工具需配置) |
常用命令速查
pnpm install # 安装所有依赖
pnpm add <pkg> # 安装生产依赖
pnpm add -D <pkg> # 安装开发依赖
pnpm add -g <pkg> # 全局安装
pnpm remove <pkg> # 卸载
pnpm update # 更新依赖
pnpm run <script> # 运行脚本
pnpm -r run <script> # 所有工作区运行脚本
pnpm --filter <pkg> <cmd> # 在指定工作区执行
pnpm list # 列出已安装包
pnpm outdated # 查看可升级包
pnpm store prune # 清理缓存