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 pnpm

2.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 pnpm

2.4 使用 Chocolatey 安装(Windows)

choco install pnpm

2.5 验证安装

pnpm --version

3. pnpm 基本命令

3.1 初始化项目

pnpm init

3.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 -i

3.4 移除依赖

# 移除指定包
pnpm remove <package>

# 移除全局包
pnpm remove -g <package>

3.5 查看依赖

# 查看项目依赖
pnpm list

# 查看指定包的信息
pnpm info <package>

# 检查依赖树
pnpm why <package>

# 查看过期依赖
pnpm outdated

3.6 运行脚本

# 运行 package.json 中的脚本
pnpm run <script>

# 运行开发脚本(快捷方式)
pnpm dev

# 运行构建脚本(快捷方式)
pnpm build

4. 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 build

4.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-store

5. 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.com

5.2 命令行配置

# 设置全局配置
pnpm config set <key> <value> --global

# 设置项目本地配置
pnpm config set <key> <value>

# 查看配置
pnpm config list

6. 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:

  1. 安装 pnpm:npm install -g pnpm
  2. 删除 node_modulespackage-lock.jsonrm -rf node_modules package-lock.json
  3. 安装依赖:pnpm install
  4. 运行测试:pnpm test

从 Yarn 迁移到 pnpm:

  1. 安装 pnpm:npm install -g pnpm
  2. 删除 node_modulesyarn.lockrm -rf node_modules yarn.lock
  3. 安装依赖:pnpm install
  4. 运行测试:pnpm test

7. 常见问题与解决方案

7.1 依赖冲突

问题:安装依赖时出现 peer dependency 冲突。

解决方案

  • 检查并更新冲突的依赖版本。
  • .npmrc 中设置 auto-install-peers=true 自动安装 peer 依赖。
  • 使用 pnpm add --save-peer &lt;package&gt; 添加缺失的 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 的核心优势在于:

  1. 速度快:安装速度比 npm 和 Yarn 都要快,特别是在重复安装时。
  2. 节省磁盘空间:相同版本的依赖只存储一次,通过符号链接引用。
  3. 严格的依赖管理:避免了依赖提升导致的版本冲突。
  4. 内置支持 monorepo:无需额外配置,易于管理多包项目。
  5. 向后兼容:兼容 npm 的命令和配置,易于迁移。

无论是小型项目还是大型 monorepo,pnpm 都能为你提供出色的依赖管理解决方案。通过掌握 pnpm 的核心功能和最佳实践,你可以更高效地管理项目依赖,提高开发效率,确保项目的稳定性和可靠性。

« 上一篇 Yarn 中文教程 下一篇 » Next.js 中文教程