5.4 4pnpm 使用介绍
- pnpm 官网:https://pnpm.io/ 高性能的 Node.js 包管理工具
一、什么是 pnpm?
pnpm(Performant npm)是一个高性能、节省磁盘空间的 Node.js 包管理工具,兼容 npm 生态。它由 Zoltan Kochan 于 2016 年创建,目标是解决 npm 和早期 yarn 在依赖管理中的性能与磁盘占用问题。
pnpm 的核心优势在于其独特的 硬链接 + 内容可寻址存储(Content-Addressable Storage, CAS) 机制,使其在安装速度、磁盘使用和依赖一致性方面表现卓越。
二、pnpm 的核心原理
1. 硬链接(Hard Links)与符号链接(Symlinks)
与 npm/yarn 直接复制依赖包不同,pnpm 使用 硬链接 来引用全局存储中的包,避免重复下载和存储。
- 全局内容存储(Content Store)
pnpm 将所有包存储在一个全局目录中(如~/.pnpm-store
),每个包只保存一份。 - 项目中使用硬链接
项目node_modules
中的依赖通过 硬链接 指向全局存储中的文件,不占用额外磁盘空间。 - 扁平化结构 + 符号链接
pnpm 使用 符号链接 构建依赖树,确保依赖可解析,同时避免“幻影依赖”(phantom dependencies)。
2. 内容可寻址存储(CAS)
包文件根据其内容生成唯一哈希值作为存储路径,确保:
- 相同内容只存储一次
- 文件完整性高(内容变化则哈希变化)
- 支持离线安装(若包已存在于 store)
3. 严格的依赖结构(Strict Node Modules)
pnpm 构建的 node_modules
是扁平且严格的,只包含项目直接依赖和其子依赖的符号链接,不会提升无关包,从而:
- 防止“幻影依赖”(即项目使用了未声明的依赖)
- 提高依赖一致性
- 减少
node_modules
体积
✅ 例如:A 依赖 B,B 依赖 C。pnpm 中 C 只在 B 的
node_modules
下,A 无法直接require('C')
,除非 A 显式声明依赖 C。
三、pnpm vs npm vs yarn:对比分析
特性 | pnpm | npm | yarn (classic) |
---|---|---|---|
安装速度 | ⚡️ 极快(硬链接) | 慢(复制文件) | 快(缓存) |
磁盘占用 | 💾 极小(全局 store) | 大(重复复制) | 较大(缓存+复制) |
依赖结构 | ✅ 严格、扁平 | ❌ 提升依赖(幻影依赖) | ❌ 提升依赖 |
离线安装 | ✅ 支持(store 存在即可) | ❌ 无缓存则失败 | ✅ 支持 |
零安装(PnP) | ❌ 不支持 | ❌ 不支持 | ✅ yarn 2+ 支持 |
钩子脚本(hooks) | ✅ 支持 pnpmfile.js | ❌ | ✅ |
工作区(Workspace) | ✅ 强大支持 | ✅ npm 7+ | ✅ |
兼容性 | ✅ 完全兼容 npm registry | ✅ | ✅ |
📌 结论:pnpm 在性能、磁盘效率和依赖安全方面全面领先。
四、快速上手:安装与基本使用
1. 安装 pnpm
# 使用 npm 安装(推荐首次安装)
npm install -g pnpm# 或使用 corepack(Node.js 16.13+ 内置)
corepack enable
corepack prepare pnpm@latest --activate# 验证安装
pnpm --version
2. 常用命令速查
命令 | 说明 |
---|---|
pnpm add <pkg> | 安装包(--save 默认) |
pnpm add -D <pkg> | 安装为开发依赖 |
pnpm add -g <pkg> | 全局安装 |
pnpm remove <pkg> | 卸载包 |
pnpm install | 安装所有依赖 |
pnpm update | 更新依赖 |
pnpm run <script> | 运行 package.json 中的脚本 |
pnpm list | 查看已安装包 |
pnpm outdated | 检查过期依赖 |
pnpm audit | 安全漏洞扫描 |
pnpm doctor | 检查环境问题 |
3. 初始化项目
pnpm init
pnpm add vue react lodash # 安装依赖
pnpm add -D typescript eslint # 安装开发依赖
五、高级特性详解
1. 工作区(Workspaces)
pnpm 支持多包项目(monorepo),通过 pnpm-workspace.yaml
管理。
# pnpm-workspace.yaml
packages:- 'packages/*'- 'apps/*'
// packages/shared/package.json
{"name": "@myorg/shared","version": "1.0.0"
}
// apps/web/package.json
{"dependencies": {"@myorg/shared": "workspace:*"}
}
使用
workspace:*
可本地链接包,无需发布即可开发调试。
2. 共享依赖存储(Shared Store)
所有项目共享同一个全局 store,默认路径:
- macOS/Linux:
~/.pnpm-store
- Windows:
%LOCALAPPDATA%\pnpm-store
可通过 .npmrc
配置:
store-dir=/path/to/custom/store
- 路径:
- macOS / Linux:
~/.npmrc
(即/Users/你的用户名/.npmrc
或/home/你的用户名/.npmrc
) - Windows:
C:\Users\你的用户名\.npmrc
- macOS / Linux:
3. pnpmfile.js:自定义行为
创建 pnpmfile.js
可拦截和修改安装行为(如替换包、重写版本)。
// pnpmfile.js
function readPackage(pkg) {// 将 lodash 替换为 lodash-esif (pkg.name === 'lodash') {pkg.name = 'lodash-es'}return pkg
}module.exports = { readPackage }
4. 选择器(Selectors)与过滤器
在工作区中精确操作子包:
# 在所有包中运行构建
pnpm -r build# 在名为 "web" 的包中安装依赖
pnpm add react --filter web# 构建依赖图中 web 包及其依赖
pnpm build --filter web...
5. 离线模式与缓存
# 强制使用缓存(离线安装)
pnpm install --offline# 查看缓存
pnpm store status# 清理无效包
pnpm store prune
六、最佳实践与注意事项
✅ 推荐做法
- 新项目优先使用 pnpm
- 性能高、节省磁盘、依赖安全。
- 启用工作区管理 Monorepo
- 使用
pnpm-workspace.yaml
统一管理多包。
- 使用
- 使用
pnpm-lock.yaml
- 锁定依赖版本,确保团队一致性。
- 定期清理 store
pnpm store prune # 删除未使用的包
- 结合
pnpm-ctl
或changesets
管理版本发布
⚠️ 注意事项
某些工具不兼容硬链接
- 如 Docker 构建、CI/CD 中需注意文件系统支持。
- 解决方案:使用
--shamefully-hoist
(不推荐)或调整 CI 配置。
避免
shamefully-hoist
pnpm install --shamefully-hoist
会提升依赖,破坏严格性,仅用于兼容旧工具。
IDE 支持
- WebStorm、VS Code 均良好支持 pnpm。
- 确保 TypeScript 路径解析正确。
迁移现有项目
# 删除 node_modules 和 lock 文件 rm -rf node_modules package-lock.json yarn.lock # 重新安装 pnpm install
七、常见问题(FAQ)
Q1: pnpm 为什么更快?
- 硬链接避免文件复制,CAS 缓存避免重复下载。
Q2: 能否与 npm/yarn 混用?
- 可以,但不推荐。混用会导致多个
node_modules
和锁文件冲突。
Q3: 如何查看全局安装的包?
pnpm list -g --depth=0
Q4: 如何发布包?
与 npm 相同:
pnpm publish
八、总结
pnpm 是当前最高效、最节省资源的 Node.js 包管理工具,特别适合:
- 大型项目或 Monorepo
- 团队协作(依赖一致性高)
- CI/CD 环境(安装快、缓存友好)
- 本地开发(节省磁盘空间)
选择 pnpm 的理由:
- ⚡️ 安装速度极快
- 💾 磁盘占用极小
- 🔒 依赖结构严格,避免幻影依赖
- 🧩 工作区支持强大
- 🔄 完全兼容 npm 生态
✅ 建议:无论是新项目还是老项目迁移,pnpm 都是当前最值得推荐的选择。