这篇不是“谁更快”的玄学讨论,而是把团队能落地的做法一次说清:如何选型、如何统一版本、如何把镜像与缓存配好、如何在 CI 和 Monorepo 下稳住“可重复构建”。
一、结论先说在前
单仓库 / 以稳定为先:直接用 npm(配合
npm ci
) 足够,维护成本低,生态一等一,Node 16.10+ 搭配 Corepack 很顺手。Monorepo / 依赖体量大 / 追求装包速度与磁盘复用:优先 pnpm。它的内容寻址仓库(store)+ 硬链接/符号链接极致省盘,装包速度很稳。
需要 PnP / Zero-Install / 插件扩展:选择 Yarn Berry(Yarn 3/4)。但默认 PnP 对部分工具有适配成本,可改为
nodeLinker: node-modules
。
团队统一的最低落地标准:
在
package.json
写死包管器:{ "packageManager": "pnpm@9.0.0" } // 或 npm@10.x / yarn@4.x
Node 16.10+:启用 Corepack 管理包管器版本:
corepack enable corepack prepare pnpm@9.0.0 --activate
提交锁文件:
package-lock.json
/yarn.lock
/pnpm-lock.yaml
必须进仓库。CI 使用不可变安装:
npm ci
、yarn install --immutable
、pnpm install --frozen-lockfile
。
二、npm / yarn / pnpm 差异速览
维度 | npm | Yarn Classic(1.x) | Yarn Berry(3/4) | pnpm |
---|---|---|---|---|
锁文件 | package-lock.json |
yarn.lock |
yarn.lock |
pnpm-lock.yaml |
安装模式 | npm ci 快速、干净 |
经典 node_modules | 默认 PnP(可切回 node_modules) | 内容寻址 store + 链接 |
Workspaces | ✅ (npm 7+) | ✅ | ✅(一流) | ✅(一流) |
依赖解析 | 较宽松(npm 7+ 自动 peer) | 较宽松 | 严格可配置 | 严格,peer 冲突更易暴露 |
离线/缓存 | 基础缓存 | --offline 有限 |
Zero-Install(可提交 .yarn/cache ) |
共享 store、pnpm fetch 、--offline |
磁盘占用 | 中等 | 中等 | 低(配合 PnP) | 最低(去重极致) |
生态兼容性 | 最佳 | 很好 | 需适配(PnP) | 很好(偶有老旧工具需 hoist) |
经验:pnpm 在大仓库更省盘稳健;Yarn Berry 在前端重仓且能接受 PnP 时很丝滑;npm 胜在“无需教育成本”。
三、国内镜像配置(含二进制依赖加速)
国内推荐统一镜像:https://registry.npmmirror.com
(原淘宝源)
3.1 全局镜像
# npm
npm config set registry https://registry.npmmirror.com
# Yarn Classic
yarn config set registry https://registry.npmmirror.com
# Yarn Berry(写入 .yarnrc.yml)
yarn config set npmRegistryServer "https://registry.npmmirror.com"
# pnpm
pnpm config set registry https://registry.npmmirror.com
3.2 项目级(推荐写入仓库,保证可重复)
.npmrc
registry=https://registry.npmmirror.com # node-gyp & 头文件镜像(按需) disturl=https://npmmirror.com/mirrors/node/ # 常见二进制包镜像(按需启用) SASS_BINARY_SITE=https://npmmirror.com/mirrors/node-sass ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ PUPPETEER_DOWNLOAD_HOST=https://npmmirror.com/mirrors SHARP_DIST_BASE_URL=https://npmmirror.com/mirrors/sharp-libvips
.yarnrc.yml
(Yarn Berry)npmRegistryServer: "https://registry.npmmirror.com" nodeLinker: node-modules # 若不想用 PnP # 可选:启用全局缓存,减少磁盘重复 enableGlobalCache: true
.npmrc
(pnpm 亦读取)或.pnpmrc
registry=https://registry.npmmirror.com # 共享仓库存放位置(提升跨项目复用) store-dir=~/.pnpm-store
二进制依赖(
sharp
、node-sass
、electron
、puppeteer
)一定要设镜像变量,否则容易超时。
四、安装命令与“不可变安装”策略
核心目标:锁文件不可被静默改写,CI 结果可重复。
npm:
npm ci # 仅根据 package-lock 安装,快且干净 npm ci --no-audit --fund=false
Yarn:
Yarn Classic:
yarn install --frozen-lockfile
Yarn Berry:
yarn install --immutable
(更严格)
pnpm:
pnpm install --frozen-lockfile # 预拉缓存(离线构建友好) pnpm fetch pnpm install --offline
五、缓存与离线优化
5.1 本机缓存目录
npm config get cache # 一般 ~/.npm/_cacache
yarn cache dir # Yarn 1 缓存目录
pnpm store path # 一般 ~/.pnpm-store
pnpm 的共享 store 可跨项目复用同一包(去重极致)。
Yarn Berry 支持 Zero-Install:把
.yarn/cache/*.zip
提交进仓库,装包无需命网。
5.2 CI 缓存(示例:GitHub Actions)
# npm
- uses: actions/cache@v4
with:
path: ~/.npm/_cacache
key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
# pnpm
- uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
# Yarn Berry(Zero-Install 推荐直接提交 .yarn/cache,无需缓存动作)
5.3 私有仓库 / 内网
用 Gitea/GitLab Package Registry / Verdaccio 搭一层私有 npm proxy。
.npmrc
针对作用域定向镜像:@your-scope:registry=https://registry.your-internal.com # 其余包仍走 npmmirror registry=https://registry.npmmirror.com
六、Monorepo 最佳实践
6.1 三家都支持 Workspaces
npm:
"workspaces": ["packages/*"]
Yarn:
workspaces: [...]
+ Berry 对 Monorepo 体验最佳(Constraints、Plugins)pnpm:
pnpm-workspace.yaml
(推荐)
pnpm 示例:
# pnpm-workspace.yaml
packages:
- "packages/*"
命令:
pnpm -r install # 递归安装
pnpm -r build # 逐包构建(可并行)
pnpm -r test --filter @proj/foo
6.2 hoist 策略与兼容性
某些老工具默认假设扁平
node_modules
,在 pnpm 严格结构下可能找不到依赖。解决:
# .npmrc 或 .pnpmrc shamefully-hoist=true # 全量提升(简单粗暴) # 或者只提升特定依赖 public-hoist-pattern[]=*eslint* public-hoist-pattern[]=*webpack*
Yarn Berry:若 PnP 兼容性有问题,改用:
nodeLinker: node-modules
七、依赖治理:overrides / resolutions / peer 依赖
7.1 锁定子依赖版本
npm(8+):
{ "overrides": { "ansi-regex": "^5.0.1", "webpack-dev-server": { "chokidar": "^3.5.3" } } }
Yarn:
{ "resolutions": { "ansi-regex": "^5.0.1" } }
pnpm:
{ "pnpm": { "overrides": { "ansi-regex": "^5.0.1" } } }
7.2 peerDependencies 策略
npm 7+ 会自动安装 peer,但冲突时经常“糊”到错误版本。
pnpm 对 peer 更严格,冲突会直接报错(优点是早暴露问题)。
Yarn Berry 可通过 Constraints/Plugins 做更强规则校验。
实战建议:把关键 peer 直接列入顶层 dependencies,减少隐式传递。
八、性能优化与安装提速清单
只走锁文件安装:
npm ci
/--immutable
/--frozen-lockfile
本地/CI 缓存配置好:pnpm 共享 store、Yarn Zero-Install
国内镜像与二进制镜像 配全,避免下载失败重试
禁用无用的审计/赞助(CI 中):
npm ci --no-audit --fund=false
Yarn Berry 默认关闭
audit
,需要时yarn npm audit
合理并发:pnpm 默认并发很高,通常不需改;npm 可
npm config set fetch-retries 5
、fetch-timeout 60000
锁文件体积与依赖瘦身:减少
^
、~
漂移;移除未用依赖;使用bundleDependencies
/optionalDependencies
有策略地控制体积
九、调试与常见错误
ELIFECYCLE / node-gyp 失败
安装编译链:
macOS:
xcode-select --install
Linux:
build-essential python3 make gcc g++
Windows:
npm i -g windows-build-tools
(或 VS Build Tools)
配置镜像:
disturl
、*_BINARY_*
环境变量(见上)
依赖“安装成功但运行找不到包”(pnpm)
老工具默认扁平结构 → 开启
shamefully-hoist
或public-hoist-pattern
Yarn Berry PnP 报模块找不到
改为
nodeLinker: node-modules
,或给工具装 PnP 插件/类型提示
锁文件频繁被改动
CI 强制:
npm ci
/--immutable
/--frozen-lockfile
团队规范:禁止手动
npm update -g
这类会影响全局的操作;锁文件冲突走再生成流程
十、CI/CD 基线模板
npm(GitHub Actions)
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci --no-audit --fund=false
- run: npm run build
pnpm
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- run: corepack enable
- run: corepack prepare pnpm@9.0.0 --activate
- run: pnpm install --frozen-lockfile
- run: pnpm -r build
Yarn Berry
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: corepack enable
- run: corepack prepare yarn@4.1.0 --activate
- run: yarn install --immutable
- run: yarn build
十一、团队约定(建议直接抄到 README)
统一 Node 与包管器版本:
engines
+packageManager
+ Corepack锁文件必须提交;任何 PR 禁止动锁文件除非升级依赖
开发装包:
npm i
/yarn
/pnpm i
CI 装包:npm ci
/yarn --immutable
/pnpm i --frozen-lockfile
国内镜像与二进制镜像变量 在根目录
.npmrc
/.yarnrc.yml
固化Monorepo 下用 pnpm 或 Yarn Berry;若第三方工具不兼容,先开启 hoist 或切回 node_modules
定期
depcheck
/npm prune
清理未用依赖,控制体积与安全风险
最后小结语
npm 胜在“即插即用”,生态与稳定性几乎无短板;
pnpm 在大仓库/多项目/重复依赖的场景里就是爽;
Yarn Berry 提供了最强可控性(PnP/插件/Zero-Install),但需要团队适配意识。