方式一:Corepack(推荐)
corepack enable # 一次性启用 corepack prepare pnpm@9.12.0 --activate pnpm --version # 9.12.0
更好的玩法:在项目 package.json 锁定版本,任何成员 cd 进来会自动用对应的 pnpm:
{
"packageManager": "pnpm@9.12.0"
}
Corepack 为什么
Node 官方项目,把 npm/pnpm/yarn 统一托管,
Node 官方项目,把 npm/pnpm/yarn 统一托管,
packageManager 字段是它的协议。团队里有人用 pnpm 8 有人用 9 是灾难;锁版本后执行 pnpm install Corepack 会自动下对应版本——不需要每人手工升级。
方式二:独立安装脚本
# macOS/Linux curl -fsSL https://get.pnpm.io/install.sh | sh - # Windows PowerShell iwr https://get.pnpm.io/install.ps1 -useb | iex
不走 Node,pnpm 变成全局二进制,启动更快。适合当主力。
方式三:npm 全局
npm install -g pnpm
最直观,但依赖当前 Node 版本——换 Node 版本要重装一次。
方式四:Homebrew / Scoop
# macOS brew install pnpm # Windows scoop install pnpm
方式五:Docker 基础镜像
FROM node:20-alpine RUN corepack enable WORKDIR /app COPY package.json pnpm-lock.yaml ./ RUN pnpm install --frozen-lockfile
pnpm init 创建项目
mkdir my-app && cd my-app pnpm init # 生成 package.json
{
"name": "my-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
跟 npm init 几乎一样——pnpm 完全兼容 package.json 语义。
添加依赖
pnpm add react react-dom pnpm add -D typescript @types/react # devDep pnpm add -O webpack # optionalDep pnpm add -P axios # peerDep(很少手工写)
别名:pnpm i = install、pnpm a = add、pnpm rm = remove、pnpm up = update、pnpm ls = list。
首次 pnpm install 发生了什么
1. 读 package.json 拿依赖树 2. 解析版本范围 → 确定具体版本(写入 pnpm-lock.yaml) 3. 检查 ~/.local/share/pnpm/store 有没有缓存 - 没有 → 下载 tarball 解压到 store - 有 → 跳过 4. 把 store 里的文件硬链接到 node_modules/.pnpm/<pkg>@<ver>/ 5. 把 package.json 声明的包 symlink 到 node_modules/ 6. 执行 postinstall 钩子
pnpm-lock.yaml
lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false importers: .: dependencies: react: specifier: ^18.3.1 version: 18.3.1 react-dom: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) packages: react@18.3.1: resolution: { integrity: sha512-xxx... } engines: { node: '>=0.10.0' } react-dom@18.3.1: resolution: { integrity: sha512-xxx... } peerDependencies: react: ^18.3.1
YAML 格式,人类可读;v9 引入了紧凑的 specifier/version 分离,冲突合并更干净。
lockfile 必须进 git
pnpm-lock.yaml 保证 CI / 队友 / 生产装出一模一样的 node_modules。不提交 = 不可复现。被 .gitignore 掉是事故常见原因。
node_modules 看起来什么样
node_modules/ ├── .modules.yaml ← pnpm 的元数据 ├── .pnpm/ │ ├── react@18.3.1/ │ │ └── node_modules/ │ │ └── react/ ← 真实文件(硬链自 store) │ ├── react-dom@18.3.1_react@18.3.1/ │ │ └── node_modules/ │ │ ├── react-dom/ │ │ └── react/ ← symlink 到上方 react@18.3.1 │ └── ... ├── react → .pnpm/react@18.3.1/node_modules/react ← symlink ├── react-dom → .pnpm/react-dom.../node_modules/react-dom ← symlink └── (不存在 lodash,即使它是某个子依赖)
几个常用命令
| 命令 | 说明 |
|---|---|
pnpm install | 按 lockfile 装齐(本地用这个) |
pnpm install --frozen-lockfile | CI 用:lockfile 不对就报错 |
pnpm install --lockfile-only | 只更新 lockfile,不装 node_modules |
pnpm add <pkg> | 加依赖到 dependencies |
pnpm remove <pkg> | 删依赖 |
pnpm update [pkg] | 按 ^ 规则升版本 |
pnpm update --latest | 升到最新 major |
pnpm outdated | 列出可升级的包 |
pnpm why <pkg> | 这个包为什么被装了(依赖链) |
pnpm dlx:临时执行
# 相当于 npx,下载 create-next-app 并跑 pnpm dlx create-next-app@latest my-app # 常用别名 pnpm dlx prettier --write .
dlx 把包下到 pnpm 的临时缓存,跑完留着下次用,比每次 npx 重下快很多。
npmrc 配置
# .npmrc(项目根 or ~/.npmrc) registry=https://registry.npmmirror.com/ auto-install-peers=true strict-peer-dependencies=false shamefully-hoist=false save-exact=true engine-strict=true
auto-install-peers
自动装 peerDependencies,v8 起默认开——历史 npm 要手动
npm install react 才能用 react-dom。shamefully-hoist
开了之后,pnpm 会把子依赖也扁平提到 node_modules 顶层——即牺牲严格性换取兼容性。遇到老包或某些打包器才用。
engine-strict
强制 Node 版本符合
engines 字段,不符合安装失败。适合生产严肃项目。国内镜像
pnpm config set registry https://registry.npmmirror.com/ # 或写到 .npmrc
清缓存
pnpm store prune # 清 store 里没引用的包 pnpm store path # 打印 store 位置 rm -rf node_modules && pnpm install # 重装本项目
本章小结
- 推荐 Corepack +
packageManager字段锁 pnpm 版本,团队一致 pnpm install= 解析 → CAS 缓存 → 硬链 → symlink;lockfile 必进 git- 常用
add/rm/up/why/dlx,语义向 npm 对齐 .npmrc配镜像、peer 策略、严格引擎- 出问题:
rm -rf node_modules + pnpm install,清 store 用pnpm store prune