npm、yarn、pnpm 有什么区别?lock 文件的作用?
包管理器对比
| 特性 | npm | yarn (v1) | pnpm |
|---|---|---|---|
| 安装速度 | 中 | 快 | 最快 |
| 磁盘空间 | 多 | 多 | 最少(硬链接) |
| 幽灵依赖 | ❌ 有 | ❌ 有 | ✅ 无 |
| 并行安装 | ❌ | ✅ | ✅ |
| Workspaces | ✅ | ✅ | ✅ |
| 插件 | ❌ | ✅ (v2+) | ✅ |
幽灵依赖问题
npm/yarn 采用扁平化 node_modules:
node_modules/
├── express/ ← 直接依赖
├── body-parser/ ← express 的依赖,被提升到顶层
├── debug/ ← body-parser 的依赖,也被提升
└── ...问题:你的代码可以 import 未在 package.json 中声明的包(被提升的依赖),这就是幽灵依赖。
// package.json 只声明了 express
// 但代码中可以引用 express 的依赖(幽灵依赖)
import parse from 'body-parser' // ✅ 能用但不应该
// 一天 express 不再依赖 body-parser,你的代码就崩了pnpm 的解决方案
pnpm 使用非扁平结构 + 硬链接:
node_modules/
├── .pnpm/ ← 真实存储位置
│ ├── express@4.18.2/
│ │ └── node_modules/
│ │ ├── express/ ← 硬链接到全局 store
│ │ └── body-parser/ ← 软链接
│ └── body-parser@1.20.1/
│ └── node_modules/
│ └── body-parser/
└── express/ ← 软链接到 .pnpm/express@4.18.2/...只有 package.json 中声明的依赖才出现在顶层 node_modules 中,彻底杜绝幽灵依赖。
pnpm 的全局 store
# 全局 store(内容寻址存储)
~/.pnpm-store/
└── v3/
└── files/
├── ab/cdef123... ← 文件按哈希存储
└── ...
# 项目中的 node_modules 通过硬链接引用
# 多个项目共享同一份文件,节省磁盘空间lock 文件
| 包管理器 | lock 文件 |
|---|---|
| npm | package-lock.json |
| yarn | yarn.lock |
| pnpm | pnpm-lock.yaml |
lock 文件的作用
- 版本锁定:确保团队/CI 安装的依赖版本完全一致
- 快速安装:跳过版本解析,直接按 lock 安装
- 安全性:防止依赖被篡改
// package-lock.json(简化)
{
"packages": {
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-..." // 完整性校验
}
}
}安装命令对比
# 安装
npm install # 安装所有依赖
pnpm install # 同上
# 添加依赖
npm install lodash # 添加到 dependencies
pnpm add lodash
# 添加开发依赖
npm install -D vitest
pnpm add -D vitest
# 全局安装(不推荐)
npm install -g pkg
pnpm add -g pkg
# 删除依赖
npm uninstall lodash
pnpm remove lodash
# 更新
npm update
pnpm updatenpm scripts 生命钩子
{
"scripts": {
"preinstall": "...", // install 前
"install": "...",
"postinstall": "...", // install 后
"prepublishOnly": "..." // 发布前
}
}推荐
- 新项目:使用 pnpm(速度快、省空间、无幽灵依赖)
- Monorepo:pnpm workspace + Turborepo
- 老项目:保持原有包管理器,迁移成本高时不必强换
.npmrc 配置
# .npmrc
registry=https://registry.npmmirror.com/ # 淘宝镜像
auto-install-peers=true
shamefully-hoist=true # 临时兼容旧工具(谨慎使用)