迁移优势:pnpm 通过硬链接共享依赖,显著减少磁盘占用、加速安装,并严格管理依赖树(避免幻影依赖)。
一、全局安装 pnpm
npm install -g pnpm
作用:确保系统有 pnpm 环境,后续命令可用 pnpm 执行。
二、清理 npm 遗留文件
# 删除 node_modules 和锁文件
rm -rf node_modules
rm package-lock.json # 或 yarn.lock(若存在)
rm npm-shrinkwrap.json # 如果存在
原因:
- 避免 npm 的
node_modules和锁文件干扰 pnpm 的依赖解析。 - pnpm 使用自己的锁文件
pnpm-lock.yaml和独特的依赖存储结构。
三、配置 pnpm 提升策略(可选但推荐)
在项目根目录创建 .npmrc 文件:
# .npmrc
shamefully-hoist=true
作用:
- 将依赖提升到根
node_modules,解决部分工具(如 Babel、ESLint)因依赖查找路径问题导致的报错。 - 保持与 npm/yarn 类似的扁平化结构,降低迁移成本。
四、安装依赖
pnpm install
过程解析:
- pnpm 读取
package.json,下载依赖到全局存储(如~/.pnpm-store)。 - 在项目内通过硬链接引用依赖,生成
pnpm-lock.yaml。 - 创建符合
shamefully-hoist规则的node_modules结构。
五、解决 Peer Dependencies 警告
npm v7+ 会自动安装 peer 依赖,而 pnpm 默认不自动安装。所以安装过程中可能出现 peer 依赖警告:
warning "eslint-plugin-react@11.1.0" has unmet peer dependency "eslint@^6.0.0 || ^7.0.0".
解决方案:
# 手动安装缺失的 peer 依赖(推荐)
pnpm add eslint@^7.0.0 -D
# 或在 `.npmrc` 中启用自动安装
auto-install-peers=true
六、更新项目脚本
修改 package.json 中的脚本命令:
{
"scripts": {
- "dev": "npm run start",
+ "dev": "pnpm start",
"build": "vite build"
}
}
原因:统一使用 pnpm 命令,避免混用 npm 导致依赖问题。
七、处理 Monorepo 项目(若适用)
-
npm v7/8 用户:若项目使用 Workspaces,需额外删除子包的
package-lock.jsonfind . -name 'package-lock.json' -delete -
删除
package.json中的workspaces字段 -
创建
pnpm-workspace.yaml:packages: - 'packages/**' -
在子包中执行
pnpm install。
作用:启用 pnpm 的 workspace 功能,优化多包依赖共享。
八、验证迁移成功
-
检查文件:
- 确认生成了
pnpm-lock.yaml。 - 检查
node_modules结构(应有.pnpm目录和软链接)。
- 确认生成了
-
运行项目:
pnpm run dev pnpm run build -
测试依赖:
pnpm test # 运行测试 ls node_modules/.pnpm # 应存在此目录
九、提交变更到 Git
git add pnpm-lock.yaml .npmrc
git commit -m "迁移到 pnpm"
注意:
- 务必将
pnpm-lock.yaml加入版本控制,确保团队依赖一致。 - 忽略
.pnpm-store(全局存储无需提交)。
常见问题解决
1. Peer 依赖是什么?
Peer Dependencies(同伴依赖)是包声明:"要使用我,你的环境里必须有 XXX 包!"(环境要求清单)
// 某个UI组件的package.json
"peerDependencies": {
"react": ">=16.8.0" // 要求用户项目自带react
}
- 避免重复安装(比如 10 个组件都依赖 React,项目只需装一次)
- 确保版本兼容(强制使用相同版本的宿主包)
2. Workspaces 是什么?
一个管理多包项目(Monorepo)的功能,允许在单个仓库中管理多个相互关联的 npm 包。(多项目共享管家) 总结:
| 问题类型 | 无 Workspaces 时 | 有 Workspaces 时 |
|---|---|---|
| 依赖安装 | 每个包独立 node_modules,磁盘占用巨大 | 所有依赖提升到根目录,硬链接共享 |
| 本地包引用 | 需要 npm publish → npm install 才能测试 | 直接本地链接,实时生效 |
| 版本管理 | 各包版本分散难同步 | 所有包版本集中管理 |
- 配置示例:
# pnpm-workspace.yaml packages: - 'packages/**' # 所有子包 - 'apps/*' # 所有应用 - '!**/test/**' # 排除测试目录
3. pnpm-lock.yaml 是什么?
pnpm 生成的依赖关系精确快照,记录每个包的确切版本和下载地址。
- 锁定所有依赖的精确版本(包括嵌套依赖)
- 存储文件的哈希值(防篡改)
- 记录依赖来源位置(加速安装)
# pnpm-lock.yaml 片段示例
dependencies:
react:
version: 18.2.0
resolution: react@18.2.0
checksum: sha512-abcdef... # 文件指纹
总结:
| 问题场景 | 无 lock 文件 | 有 lock 文件 |
|---|---|---|
| 安装一致性 | 开发者A可能装到1.0.0,开发者B装到1.0.1 | 所有人锁定到完全相同的版本 |
| 依赖树变化 | 同一份 package.json 可能安装出不同的嵌套结构 | 依赖树结构被冻结 |
| 安全审计 | 无法追踪实际安装的依赖 | 明确知道每个包的具体版本和来源 |
4. 命令找不到(如 vue-cli-service)
原因:npm 会将可执行文件软链接到 ./node_modules/.bin,而 pnpm 使用嵌套结构。
修复:
# 方案一:使用 pnpm dlx 执行(临时)
pnpm dlx vue-cli-service serve
# 方案二:在 scripts 中直接写完整路径
"scripts": {
"serve": "./node_modules/.bin/vue-cli-service serve"
}
5. 依赖重复安装
原因:子依赖版本冲突时,pnpm 会安装多份(符合预期)。
检查:
pnpm why <package> # 查看依赖被哪些包引用
6. npm 版本差异对迁移的影响
| npm 版本 | 关键特性 | 迁移注意事项 |
|---|---|---|
| v6 | • 默认生成 package-lock.json v1 • 不自动安装 peerDependencies | 迁移最简单,peer 依赖问题较少 |
| v7+ | • 生成 package-lock.json v2 • 自动安装 peerDependencies • 内置 Workspaces 支持 | 需特别注意 peer 依赖和 Workspaces 处理 |
| v8+ | • 同 v7 • 增强安全审计功能 | 同 v7 |
7. 若迁移后出现依赖问题
-
生成依赖树报告:
pnpm why <package-name> -
重置依赖(核武器):
rm -rf node_modules pnpm-lock.yaml pnpm install