pnpm 中文教程
1. 什么是 pnpm?
pnpm(Performant NPM)是一个快速、节省磁盘空间的 JavaScript 包管理器,由 Zoltan Kochan 创建。pnpm 使用符号链接(symlinks)和硬链接(hard links)来管理依赖,避免了依赖的重复安装,从而大大节省了磁盘空间并提高了安装速度。
1.1 pnpm 的核心优势
- 速度快:pnpm 的安装速度比 npm 和 Yarn 都要快,特别是在重复安装时。
- 节省磁盘空间:pnpm 使用内容寻址存储,相同版本的依赖只存储一次,通过符号链接引用。
- 严格的依赖管理:pnpm 默认使用严格的依赖解析,避免了依赖提升导致的版本冲突。
- 支持 monorepo:pnpm 内置支持 monorepo 管理,无需额外配置。
- 向后兼容:pnpm 兼容 npm 的命令和配置,易于迁移。
2. 安装 pnpm
2.1 使用 npm 安装
npm install -g pnpm2.2 使用独立脚本安装
# Windows (PowerShell)
iwr https://get.pnpm.io/install.ps1 -useb | iex
# macOS, Linux (Bash)
curl -fsSL https://get.pnpm.io/install.sh | sh -2.3 使用 Homebrew 安装(macOS)
brew install pnpm2.4 使用 Chocolatey 安装(Windows)
choco install pnpm2.5 验证安装
pnpm --version3. pnpm 基本命令
3.1 初始化项目
pnpm init3.2 安装依赖
# 安装所有依赖
pnpm install
# 安装指定包
pnpm add <package>
# 安装开发依赖
pnpm add -D <package>
# 安装全局包
pnpm add -g <package>
# 安装指定版本
pnpm add <package>@<version>3.3 更新依赖
# 更新所有依赖
pnpm update
# 更新指定包
pnpm update <package>
# 更新到指定版本
pnpm update <package>@<version>
# 交互式更新
pnpm update -i3.4 移除依赖
# 移除指定包
pnpm remove <package>
# 移除全局包
pnpm remove -g <package>3.5 查看依赖
# 查看项目依赖
pnpm list
# 查看指定包的信息
pnpm info <package>
# 检查依赖树
pnpm why <package>
# 查看过期依赖
pnpm outdated3.6 运行脚本
# 运行 package.json 中的脚本
pnpm run <script>
# 运行开发脚本(快捷方式)
pnpm dev
# 运行构建脚本(快捷方式)
pnpm build4. pnpm 核心功能
4.1 Workspaces(Monorepo 支持)
pnpm Workspaces 允许在单个代码仓库中管理多个包,共享依赖,减少重复安装。
配置示例:
// package.json
{
"private": true,
"workspaces": [
"packages/*"
]
}使用方法:
# 在根目录安装所有工作区依赖
pnpm install
# 在指定工作区安装依赖
pnpm --filter <package-name> add <dependency>
# 在所有工作区运行脚本
pnpm -r run <script>
# 递归构建所有工作区
pnpm -r build4.2 内容寻址存储
pnpm 使用内容寻址存储来存储依赖,相同版本的依赖只存储一次,通过符号链接引用。
存储结构:
.pnpm/store:全局存储所有依赖包的内容node_modules/.pnpm:项目本地的依赖链接node_modules:通过符号链接指向.pnpm中的依赖
优势:
- 节省磁盘空间:相同版本的依赖只存储一次
- 提高安装速度:重复安装时直接使用缓存
- 避免依赖冲突:每个包都有自己的依赖版本
4.3 严格的依赖管理
pnpm 默认使用严格的依赖解析,只有在 package.json 中明确声明的依赖才会被添加到项目的依赖树中,避免了依赖提升导致的版本冲突。
配置示例:
// .npmrc
strict-peer-dependencies=true使用严格模式的好处:
- 避免隐式依赖导致的版本冲突
- 提高项目的可重复性和稳定性
- 便于调试和排查依赖问题
4.4 零安装
pnpm 支持零安装(Zero-Installs),将依赖存储在项目的 .pnpm-store 目录中,提交到版本控制系统,使项目在克隆后无需运行 pnpm install 即可直接使用。
配置示例:
// .npmrc
store-dir=.pnpm-store
// .gitignore
node_modules
.pnpm-store/**/_lock使用方法:
# 启用零安装
pnpm install --store=local
# 提交 .pnpm-store 到版本控制系统
git add .pnpm-store5. pnpm 配置
5.1 配置文件
pnpm 使用 .npmrc 文件进行配置,支持全局配置和项目本地配置。
常用配置项:
# .npmrc
# 存储目录
store-dir=~/.pnpm-store
# 启用严格的 peer 依赖检查
strict-peer-dependencies=true
# 启用自动安装 peer 依赖
auto-install-peers=true
# 依赖解析策略(hoisted, isolated, strict)
node-linker=isolated
# 注册表
registry=https://registry.npmmirror.com5.2 命令行配置
# 设置全局配置
pnpm config set <key> <value> --global
# 设置项目本地配置
pnpm config set <key> <value>
# 查看配置
pnpm config list6. pnpm 最佳实践
6.1 依赖管理最佳实践
- 使用精确版本:在
package.json中使用精确的依赖版本,避免意外的版本更新。 - 定期更新依赖:使用
pnpm update -i定期检查和更新依赖,确保使用最新的安全补丁。 - 锁定依赖版本:提交
pnpm-lock.yaml文件到版本控制系统,确保团队成员使用相同的依赖版本。 - 使用 peerDependencies:对于插件类库,使用
peerDependencies声明对宿主库的依赖要求。
6.2 Monorepo 最佳实践
- 合理划分包:将相关功能划分为独立的包,保持包的职责单一。
- 共享配置:在根目录配置共享的工具链和脚本,如 ESLint、Prettier 等。
- 使用工作区脚本:在根目录定义工作区脚本,统一管理构建、测试等流程。
- 避免循环依赖:确保工作区之间没有循环依赖,保持依赖关系清晰。
示例 monorepo 结构:
my-monorepo/
├── package.json # 根配置,定义工作区
├── pnpm-workspace.yaml # 工作区配置
├── .pnpm-store/ # 零安装存储
├── packages/
│ ├── app/ # 主应用
│ │ ├── package.json
│ │ └── src/
│ ├── ui/ # UI 组件库
│ │ ├── package.json
│ │ └── src/
│ └── utils/ # 工具库
│ ├── package.json
│ └── src/
└── scripts/ # 共享脚本6.3 性能优化
- 使用缓存:pnpm 会自动缓存依赖,减少重复下载。
- 启用零安装:对于团队协作项目,启用零安装可以减少安装时间。
- 合理配置存储位置:将存储目录配置在 SSD 上可以提高性能。
- 使用并行命令:对于 monorepo 项目,使用
-r --parallel选项并行运行脚本。
6.4 迁移策略
从 npm 迁移到 pnpm:
- 安装 pnpm:
npm install -g pnpm - 删除
node_modules和package-lock.json:rm -rf node_modules package-lock.json - 安装依赖:
pnpm install - 运行测试:
pnpm test
从 Yarn 迁移到 pnpm:
- 安装 pnpm:
npm install -g pnpm - 删除
node_modules和yarn.lock:rm -rf node_modules yarn.lock - 安装依赖:
pnpm install - 运行测试:
pnpm test
7. 常见问题与解决方案
7.1 依赖冲突
问题:安装依赖时出现 peer dependency 冲突。
解决方案:
- 检查并更新冲突的依赖版本。
- 在
.npmrc中设置auto-install-peers=true自动安装 peer 依赖。 - 使用
pnpm add --save-peer <package>添加缺失的 peer 依赖。
7.2 符号链接问题
问题:在某些环境中,符号链接可能会导致问题。
解决方案:
- 在
.npmrc中设置node-linker=hoisted使用传统的依赖提升模式。 - 对于 Windows 用户,确保启用了符号链接支持。
7.3 零安装性能问题
问题:启用零安装后,版本控制系统的性能下降。
解决方案:
- 在
.gitignore中添加.pnpm-store/**/_lock忽略锁文件。 - 对于大型项目,可以考虑不使用零安装,而是使用 CI/CD 缓存。
7.4 与其他工具的兼容性
问题:某些工具可能不支持 pnpm 的符号链接结构。
解决方案:
- 检查工具的文档,看是否支持 pnpm。
- 对于不支持的工具,可以在
.npmrc中设置node-linker=hoisted。
8. 总结
pnpm 是一个现代化的 JavaScript 包管理器,它通过创新的内容寻址存储和符号链接机制,解决了 npm 和 Yarn 的许多痛点,为开发者提供了更快速、更节省空间、更可靠的依赖管理体验。
pnpm 的核心优势在于:
- 速度快:安装速度比 npm 和 Yarn 都要快,特别是在重复安装时。
- 节省磁盘空间:相同版本的依赖只存储一次,通过符号链接引用。
- 严格的依赖管理:避免了依赖提升导致的版本冲突。
- 内置支持 monorepo:无需额外配置,易于管理多包项目。
- 向后兼容:兼容 npm 的命令和配置,易于迁移。
无论是小型项目还是大型 monorepo,pnpm 都能为你提供出色的依赖管理解决方案。通过掌握 pnpm 的核心功能和最佳实践,你可以更高效地管理项目依赖,提高开发效率,确保项目的稳定性和可靠性。