Skip to content

pnpm 常用命令

pnpm(Performant npm)是一个快速、节省磁盘空间的包管理器,通过硬链接和符号链接共享依赖,避免重复安装,天然解决幽灵依赖问题。


安装

bash
# 通过 npm 全局安装
npm install -g pnpm

# 通过 corepack 启用(Node.js 16.13+)
# Corepack 是 Node.js 内置的包管理器管理工具
corepack enable
corepack prepare pnpm@latest --activate

# 通过 Homebrew(macOS)
brew install pnpm

# 通过独立脚本(Linux/macOS)
curl -fsSL https://get.pnpm.io/install.sh | sh -

# 查看版本
pnpm -v

项目初始化

bash
# 初始化新项目
pnpm init

# 跳过问答,生成默认配置
# -y 表示 yes,所有选项使用默认值
pnpm init -y

依赖管理

四种依赖类型说明

类型安装命令说明大白话解释使用场景
dependenciespnpm add <pkg>生产环境依赖项目运行必须用到的包vue、react、axios、lodash 等
devDependenciespnpm add -D <pkg>开发环境依赖只在开发时用,打包后不需要vite、eslint、typescript、jest 等
peerDependenciespnpm add -P <pkg>对等依赖你的包「期望」使用者自己安装的依赖组件库期望使用者已安装 vue
optionalDependenciespnpm add -O <pkg>可选依赖安装失败不会报错,项目照样能跑跨平台兼容包、性能优化包

安装依赖

bash
# 安装所有依赖(根据 pnpm-lock.yaml)
pnpm install
pnpm i                        # 简写,效果一样

# 安装指定包(添加到 dependencies)
pnpm add <package>

# 安装指定包(添加到 devDependencies)
# -D 是 --save-dev 的简写,表示只在开发环境使用
pnpm add -D <package>

# 安装指定版本
pnpm add <package>@1.2.3

# 安装最新版本
pnpm add <package>@latest

# 安装到 peerDependencies
# -P 是 --save-peer 的简写
pnpm add -P <package>

# 安装到 optionalDependencies
# -O 是 --save-optional 的简写
pnpm add -O <package>

# 全局安装
# -g 是 --global 的简写,全局安装的包可以在任何地方使用命令
pnpm add -g <package>

# 安装并锁定精确版本(不用 ^ 和 ~)
# --save-exact 表示精确版本,不加版本前缀
pnpm add <package>@1.2.3 --save-exact

# 安装 Git 仓库(直接从 GitHub 安装)
pnpm add github:user/repo
pnpm add git+https://github.com/user/repo.git

# 安装本地包(本地开发调试)
pnpm add file:../my-local-package
pnpm add ../my-local-package

升级 & 卸载

bash
# 升级指定包(遵守 package.json 中的版本范围)
pnpm update <package>
pnpm up <package>             # 简写

# 升级到最新版本(忽略版本范围,直接装最新)
# --latest 表示忽略版本范围,使用 npm 上的最新版本
pnpm update <package> --latest

# 升级所有依赖
pnpm update
pnpm up                       # 简写

# 交互式升级(交互式界面,可以选择要升级的包)
pnpm update --interactive
pnpm up -i                    # 简写

# 卸载指定包
pnpm remove <package>
pnpm rm <package>             # 简写
pnpm un <package>             # 更短的简写

# 全局卸载
pnpm remove -g <package>

查看依赖

bash
# 列出已安装的包(树形结构)
pnpm list
pnpm ls                       # 简写

# 只列出顶层依赖(不显示嵌套的子依赖)
# --depth 控制显示层级,0 表示只显示顶层
pnpm ls --depth=0

# 列出全局安装的包
pnpm ls -g

# 查看某个包的详细信息(版本、依赖、仓库、作者等)
pnpm info <package>
pnpm view <package>

# 查看包的所有历史版本
pnpm info <package> versions

# 查看为什么安装了某个包(显示依赖链,知道是谁引入的)
pnpm why <package>

# 检查过期依赖(显示当前版本、期望版本、最新版本)
pnpm outdated

运行脚本

bash
# 运行 package.json 中定义的脚本
# pnpm 不需要 run 关键字,直接 pnpm <script-name>
pnpm <script-name>
pnpm run <script-name>        # 完整写法

# 常见脚本
pnpm dev                       # 启动开发服务器
pnpm build                     # 构建生产版本
pnpm test                      # 运行测试

# 传递参数给脚本
# -- 是参数分隔符,用于区分 pnpm 本身的参数和脚本的参数
# -- 之后的所有参数都会传递给脚本
pnpm <script-name> -- <args>

# 可以传递多个参数
pnpm build -- --mode production --verbose

# 常见工具参数示例:

# Vite 构建工具:
pnpm dev -- --port 3001           # 指定开发服务器端口
pnpm dev -- --host                # 允许外部访问(局域网其他设备可访问)
pnpm build -- --mode staging      # 指定构建模式(staging 是预发布环境)
pnpm build -- --outDir dist2      # 指定输出目录

# ESLint 代码检查:
pnpm lint -- --fix                # 自动修复可修复的问题
pnpm lint -- --ext .js,.ts        # 指定检查的文件扩展名(ESLint 9+ 已废弃此参数)
pnpm lint -- --no-error-on-unmatched-pattern  # 无匹配文件时不报错

# Vitest 测试框架:
pnpm test -- --watch              # 监听模式,文件变化时重新测试
pnpm test -- --coverage           # 生成测试覆盖率报告
pnpm test -- --reporter verbose   # 使用详细报告器
pnpm test -- --bail 1             # 第一个测试失败后停止

# TypeScript 编译器:
pnpm build -- --noEmit            # 只检查类型,不输出文件(常用于类型检查)
pnpm build -- --sourceMap         # 生成 source map(调试时定位源码)
pnpm build -- --watch             # 监听模式,文件变化时自动编译

# 查看所有可用脚本
pnpm run

# 并行执行多个脚本
# --parallel 表示并行执行,多个脚本同时运行
pnpm run --parallel dev build

📖 创建自定义脚本的详细方法请参考 npm 常用命令


npx 替代:pnpm dlx

bash
# 直接运行包中的命令(无需安装,临时下载执行)
pnpm dlx create-vite my-app
pnpm dlx eslint --init
pnpm dlx degit user/repo my-app

# 指定版本
pnpm dlx <package>@<version>

依赖检查

bash
# 安全漏洞检查
pnpm audit

# 查看审计报告(JSON 格式,便于程序处理)
pnpm audit --json

# 自动修复安全漏洞
pnpm audit fix

CI/CD 安装

bash
# CI/CD 推荐用法:先 fetch 再 install
# pnpm fetch 只下载 pnpm-lock.yaml 中记录的包,跳过解析 package.json,速度更快
pnpm fetch

# --offline 表示只从本地缓存安装,不联网下载
pnpm install --offline

⚠️ --offline 要求本地缓存中已有所有依赖包,否则会安装失败。CI 环境首次运行需先执行 pnpm fetch 填充缓存,或确保 CI 缓存了 pnpm store。

pnpm install vs pnpm fetch + pnpm install --offline

特性pnpm installpnpm fetch + install --offline
解析 package.json否(跳过)
下载依赖是(fetch 阶段)
安装依赖是(install 阶段)
速度较慢更快
适用场景本地开发CI/CD、自动化部署

通俗解释

  • pnpm install:智能安装,会解析 package.json 并下载依赖,适合本地开发
  • pnpm fetch + pnpm install --offline:分两步走,先下载再安装,跳过解析步骤,适合 CI/CD 环境

工作空间(Monorepo)

什么是 Monorepo?

Monorepo(单一仓库)是一种项目管理方式:把多个相关的项目(包)放在同一个代码仓库中管理。

传统方式(Multirepo)

repo-utils/          # 独立仓库
  └── package.json

repo-components/     # 独立仓库
  └── package.json

repo-app/            # 独立仓库
  └── package.json

Monorepo 方式

my-project/          # 一个仓库
├── package.json     # 根配置
├── packages/
│   ├── utils/       # 工具库
│   │   └── package.json
│   └── components/  # 组件库
│       └── package.json
└── apps/
    ├── web/         # Web 应用
    │   └── package.json
    └── admin/       # 后台管理
        └── package.json

为什么用 Monorepo?

场景传统方式Monorepo
多个项目共享代码需要发布 npm 包再引用直接引用本地包,实时生效
修改一个库需要同时改多个项目需要修改多个仓库一个仓库内统一修改
统一代码规范和构建工具每个仓库单独配置根目录统一配置
查看某次修改影响了哪些项目需要跨仓库搜索一个仓库内搜索

什么时候用 Monorepo?

适合

  • 前端组件库 + 多个使用该组件库的项目
  • 后端微服务(多个服务共享工具库)
  • 全栈项目(前端 + 后端 + 共享类型定义)
  • 工具库开发(一个仓库维护多个 npm 包)

不适合

  • 完全独立的项目(没有共享代码)
  • 团队成员不熟悉 Monorepo
  • 项目非常大(Git 仓库超过几个 GB)

pnpm 工作空间配置

pnpm 对 monorepo 有出色的支持,通过 pnpm-workspace.yaml 文件配置:

yaml
# pnpm-workspace.yaml
packages:
  - 'packages/*'              # packages 目录下的所有子目录
  - 'apps/*'                  # apps 目录下的所有子目录
  - 'tools/*'                 # tools 目录下的所有子目录
  - '!**/test/**'             # 排除测试目录(! 表示排除)

常用命令

bash
# 安装所有工作空间的依赖(根目录执行一次即可,自动安装所有子项目的依赖)
pnpm install
pnpm i

# 在所有工作空间中执行命令
# -r 是 --recursive 的简写,表示递归执行
pnpm -r run build
pnpm -r build                 # 简写

# 在指定工作空间中执行
# --filter 按包名过滤
pnpm --filter <package-name> run build
pnpm -F <package-name> build  # 简写

# 在匹配的工作空间中执行(支持通配符)
pnpm --filter "@my-org/*" run test
pnpm -F "@my-org/*" test

# 根据依赖关系排序执行(拓扑排序,先执行被依赖的包)
pnpm -r --sort run build

# 添加依赖到指定工作空间
pnpm --filter <package-name> add <dependency>

# 添加公共依赖到根目录
# -w 表示根目录(workspace root)
pnpm add -w -D <package>

# 在所有工作空间中添加依赖
pnpm -r add <package>

# 过滤执行(包含依赖项)
# ... 表示包含依赖项,先执行依赖项再执行当前包
pnpm --filter <package-name>... run build

# 只在有该脚本的工作空间执行(没有该脚本的跳过)
pnpm -r run build --if-present

工作空间之间互相引用

pnpm 支持 workspace: 协议,明确引用本地包:

json
// apps/web/package.json
{
  "dependencies": {
    "@my-org/utils": "workspace:*",           // 引用本地 utils,任何版本
    "@my-org/components": "workspace:^1.0.0"  // 引用本地 components,^1.0.0 范围
  }
}

workspace:* 表示使用本地最新版本,发布时会自动替换为实际版本号。


高级功能

pnpm patch(补丁修改)

什么是 patch?什么时候用?

当你使用的某个 npm 包有 bug,但上游还没修复时,你可以用 patch 直接修改 node_modules 中的包,并生成一个补丁文件。这个补丁会被记录在项目中,其他人安装依赖时会自动应用这个补丁。

典型场景:

  • 第三方包有个小 bug,但作者迟迟不修复
  • 需要临时修改某个包的行为,等上游修复后再移除
bash
# 开始编辑某个包(会打开一个临时目录让你修改)
pnpm patch <package>

# 修改文件后,生成补丁文件
pnpm patch-commit <patch-dir>

# 补丁文件保存在 patches/ 目录
# patches/<package>+<version>.patch

pnpm deploy(部署)

什么是 deploy?什么时候用?

在 Monorepo 中,你可能只想部署某个子包(比如只部署 apps/web),而不需要整个仓库。pnpm deploy 会把指定包及其依赖打包到一个目录中,适合 Docker 镜像构建、Serverless 部署等场景。

为什么不用直接复制?

  • deploy 会自动分析依赖关系,只打包需要的文件
  • 输出的目录可以直接运行,不需要再 install
bash
# 将指定包部署到目标目录
pnpm --filter <package-name> deploy ./deploy-output

pnpm fetch(CI 优化)

什么是 fetch?什么时候用?

pnpm fetch 是 CI/CD 专用命令。它只下载 pnpm-lock.yaml 中记录的包,跳过解析 package.json 的步骤,速度更快且保证安装结果与本地完全一致。

为什么不用 pnpm install?

  • fetch 跳过了依赖解析步骤,只做下载,更快
  • 严格按 lock 文件安装,不会意外更新依赖
bash
# CI/CD 推荐用法
pnpm fetch
pnpm install --offline

pnpm-lock.yaml 文件

什么是 pnpm-lock.yaml 文件?

pnpm-lock.yaml 是 pnpm 自动生成的依赖锁定文件,记录了每个依赖的精确版本下载地址

为什么需要 pnpm-lock.yaml?

问题没有 lock 文件有 lock 文件
版本不一致不同环境安装的版本可能不同所有环境安装完全相同的版本
构建失败依赖更新导致构建失败依赖版本固定,构建稳定
协作问题团队成员依赖版本不一致团队成员使用相同版本

pnpm-lock.yaml 必须提交到 Git

bash
# .gitignore 中不要忽略 pnpm-lock.yaml
# 但要忽略 node_modules
node_modules/

pnpm-lock.yaml 冲突解决

bash
# 方案一:删除重新安装(简单粗暴,推荐新手)
rm -rf node_modules pnpm-lock.yaml
pnpm install

# 方案二:使用 Git 合并后重新安装
git checkout --theirs pnpm-lock.yaml
pnpm install

缓存管理

bash
# 查看缓存目录路径
pnpm store path

# 查看缓存状态(哪些包被缓存了)
pnpm store status

# 清除未使用的缓存(删除不再需要的包)
pnpm store prune

# 查看全局存储中的包
pnpm store list

缓存的作用

  • 提升安装速度:已下载的包会缓存,下次安装直接从缓存读取
  • 节省磁盘空间:pnpm 使用硬链接,多个项目共享同一份缓存
  • 离线安装:有缓存时可以离线安装(部分场景)

什么时候需要清理缓存?

  • 安装失败且提示缓存相关错误
  • 缓存占用空间过大
  • 切换镜像源后需要清理旧缓存

配置管理

bash
# 查看所有配置
pnpm config list

# 设置镜像源(国内用户推荐使用淘宝镜像)
pnpm config set registry https://registry.npmmirror.com

# 查看当前镜像源
pnpm config get registry

# 恢复默认镜像源
pnpm config set registry https://registry.npmjs.org

# 编辑配置文件
pnpm config edit

.npmrc 配置

pnpm 兼容 .npmrc 配置文件:

bash
# .npmrc

# 镜像源配置(国内用户推荐使用淘宝镜像)
registry=https://registry.npmmirror.com

# 依赖提升策略
# true:将所有依赖提升到根 node_modules(失去严格隔离优势,慎用)
shamefully-hoist=true

# 严格模式(默认开启,禁止未声明的依赖)
# false:允许未声明的依赖(不推荐)
strict-peer-dependencies=false

# 自动安装 Peer Dependencies
auto-install-peers=true

# 排除的包(不提升到根 node_modules)
# 只提升匹配的包到根 node_modules
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*

# 忽略生命周期脚本(安全考虑,防止恶意脚本)
ignore-scripts=false

# 存储目录(全局缓存位置)
store-dir=~/.pnpm-store

# 虚拟存储目录(node_modules 中的 .pnpm 目录)
virtual-store-dir=node_modules/.pnpm

pnpm 配置项

bash
# 设置并发数(同时下载的包数量,网络好可以设大)
pnpm config set network-concurrency 16

# 设置超时(下载包的超时时间,单位毫秒)
pnpm config set fetch-timeout 60000

# 设置重试次数(下载失败后的重试次数)
pnpm config set fetch-retries 5

# 锁文件(是否自动生成 pnpm-lock.yaml)
pnpm config set lockfile true

# 忽略 pnpm-lock.yaml 中的时间戳(解决冲突时有用)
pnpm config set lockfile-allow-timestamps true

pnpm 与其他包管理器的区别

特性npmyarnpnpmcnpm
安装速度中等快(国内)
磁盘占用小(硬链接)
依赖提升扁平化扁平化严格隔离扁平化
Monorepo 支持一般优秀一般
锁文件package-lock.jsonyarn.lockpnpm-lock.yamlpackage-lock.json(9.x 支持)
幽灵依赖存在存在不存在存在
node_modules 结构扁平扁平符号链接 + 硬链接扁平
CI 缓存npm ci--frozen-lockfilepnpm fetchnpm ci --registry=...

幽灵依赖问题

npm 和 yarn 的扁平化 node_modules 结构会导致幽灵依赖——你可以引用没有在 package.json 中声明的依赖。pnpm 使用符号链接,严格隔离,只有声明的依赖才能被引用。

node_modules 结构对比

npm/yarn(扁平化):
node_modules/
├── a/
├── b/          ← 幽灵依赖(未声明但可用)
├── c/
└── node_modules/
    └── d/      ← 嵌套依赖

pnpm(严格隔离):
node_modules/
├── .pnpm/      ← 全局存储的硬链接
│   ├── [email protected]/
│   ├── [email protected]/
│   └── [email protected]/
├── a → .pnpm/[email protected]/node_modules/a  ← 符号链接
├── b → .pnpm/[email protected]/node_modules/b
└── c → .pnpm/[email protected]/node_modules/c

常见问题

切换包管理器

bash
# 从 npm 切换到 pnpm
rm -rf node_modules package-lock.json
pnpm install

# 从 yarn 切换到 pnpm
rm -rf node_modules yarn.lock
pnpm install

安装速度慢

bash
# 使用淘宝镜像源(推荐国内用户)
pnpm config set registry https://registry.npmmirror.com

依赖提升问题

某些包可能因为严格隔离而报错,可以配置提升策略:

bash
# 在 .npmrc 中设置(全局提升,慎用)
shamefully-hoist=true

# 推荐:只提升特定包
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*

⚠️ shamefully-hoist=true 会将依赖提升到根 node_modules,失去严格隔离的优势,仅在必要时使用。

锁文件冲突

bash
# 删除重新生成(简单粗暴,推荐新手)
rm -rf node_modules pnpm-lock.yaml
pnpm install

# 或者使用 git 合并后重新安装
git checkout --theirs pnpm-lock.yaml
pnpm install

旧版本 Node.js 兼容

bash
# pnpm 8+ 需要 Node.js 16+
# 使用 corepack 指定 pnpm 版本
corepack prepare pnpm@7 --activate

参考

个人学习笔记,部分内容借助 AI 辅助整理,仅供查阅参考,请以官方文档为准