项目背景
新建使用 pnpm 管理的 Monorepo 项目 (pnpm 版本 9.1.0), 大致目录结构:
- apps (应用)
- packages (通用)
- pnpm-workspace.yaml
- package.json
由多个新老项目合并重构, 放在 apps 中, 部分常用逻辑和配置拆分打散放到 packages
几个老项目用的 yarn 作为包管理, 替换为 pnpm 时, 会出现一些问题:
- 依赖缺失, 因为
pnpm比yarn更加严格, 未在根部或当前包 (包括apps) 安装依赖时, 无法正确引入依赖 - 依赖多个, 因为
pnpm比yarn更加严格, 两个包有相同的依赖但依赖版本不一致时, 会出现多个依赖实例, 互相是隔离的, 而yarn只会使用一个
解决方法
以 ethers 包为例, 它的 5.x 和 6.x 版本只能说完全是俩东西, 但一些老项目或很久未更新的三方依赖中, 没有对 ethers 包进行版本限制, 导致本来该使用 5.x 版本的包安装了 6.x 版本, 从而引发各种报错
1. 在 package.json 中使用 pnpm 配置
(写在前面, 不好用, 一直未生效)
文档传送门: pnpm.io/zh/package_…
使用 pnpm 的 overrides 来进行重载:
// package.json (root)
{
"pnpm": {
"overrides": {
"ethers": "5.7.2"
}
}
}
删除 lock 文件后重新安装, 但没有生效, 文档说明在根路径的 package.json 中使用, 所以没有尝试在子包中配置, 这里 mark 一下
2. 使用 pnpmfile.cjs 脚本
(写在前面, 好用, 但写着麻烦)
文档传送门: pnpm.io/zh/pnpmfile
// pnpmfile.cjs
module.exports = {
hooks: {
readPackage: pkg => {
if (pkg.dependencies.ethers) {
pkg.dependencies.ethers = '5.7.2'
}
if (pkg.devDependencies.ethers) {
pkg.devDependencies.ethers = '5.7.2'
}
if (pkg.peerDependencies.ethers) {
pkg.peerDependencies.ethers = '5.7.2'
}
return pkg
},
},
}
pnpm 确实好用, 这个文件比较灵活, 就是 cjs 没有 ts 写的习惯
3. 使用 package.json 中的 resolutions 属性
(写在前面, 好用, 简单)
文档传送门: 没找到
// package.json (root)
{
"resolutions": {
"ethers": "5.7.2"
}
}
没在 npm 官网找到 resolutions 的文档, 可以看一下它的 overrides: docs.npmjs.com/cli/v10/con…
pnpm 在找到了 resolutions 的相关说明: pnpm.io/zh/package_…
搬运如下:
Functionally identical to pnpm.overrides, this field is intended to make it easier to migrate from Yarn.
resolutions and pnpm.overrides get merged before package resolution (with pnpm.overrides taking precedence), which can be useful when you're migrating from Yarn and need to tweak a few packages just for pnpm.
大体意思:
这个 resolutions 字段和 pnpm.overrides 字段功能相同, 但我的 pnpm.overrides 优先级更高
这俩都是为了更容易的从 yarn 迁移
结束