https://github.com/sooniter/how-to-lock-version
前端依赖问题解决方案
https://github.com/sooniter/how-to-lock-version
node npm pnpm
Last synced: 4 months ago
JSON representation
前端依赖问题解决方案
- Host: GitHub
- URL: https://github.com/sooniter/how-to-lock-version
- Owner: SoonIter
- Created: 2023-03-06T07:10:39.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2024-05-03T13:09:49.000Z (about 2 years ago)
- Last Synced: 2025-10-12T10:57:32.604Z (8 months ago)
- Topics: node, npm, pnpm
- Language: JavaScript
- Homepage:
- Size: 13.7 KB
- Stars: 5
- Watchers: 1
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# how to lock version ?
已经更新,移动到 [https://rsdoctor.dev/zh/blog/topic/duplicate-pkg-problem](https://rsdoctor.dev/zh/blog/topic/duplicate-pkg-problem)
Updated, moved to [https://rsdoctor.dev/blog/topic/duplicate-pkg-problem](https://rsdoctor.dev/blog/topic/duplicate-pkg-problem)
---
# 依赖层面
pnpm 里锁依赖:某一依赖使用某一确定的版本,分为 "子workspace的直接依赖" 和 "第三方包的直接依赖"
## 子workspace 的直接依赖
直接依赖直接通过 package.json 声明,确定某一版本,无需使用任何 hack
如 某个子 workspace 确定 react 的版本为
```json5
{
"name": "a",
"dependencies": {
"react": "18.2.0"
}
}
```
每个独立的包都有 `确定直接依赖` 的能力,直接依赖再确定直接依赖的直接依赖,以此递归来组成整个 `node_modules` 的版本
## 第三方包的直接依赖 (overrides and .pnpmfile.cjs)
这里第三方包的直接依赖,相对于 子workspace 来说就是间接依赖
理解了 `覆写 package.json 来确定直接依赖的版本` ,也可以更改第三方包的直接依赖
以 overrides 为例,pnpm 提供了以 `"a>b":"版本号"` 的方式来覆写 `package.json`
```json5
{
"pnpm": {
"overrides": {
"react@18.2.0>loose-envify": "1.0.0", // 1
"react>loose-envify": "1.0.0", // 2
"loose-envify": "1.0.0" // 3
}
}
}
```
**1. `"react@18.2.0>loose-envify": "1.0.0"`**
在 `"react@18.2.0"` 的 `package.json`,改写 `loose-envify` 的版本为 1.0.0,无论 "dependencies" 还是 "devDependencies"
**2. `"react>loose-envify": "1.0.0"`**
`react@*>loose-envify`
在 `"react@*"`(所有react版本,react@16 react@17 react@18等) 的 `package.json` 覆写 `loose-envify` 的版本为 1.0.0
**3. `"loose-envify": "1.0.0"`**
`*>loose-envify`
在 所有包的 `package.json` 覆写`loose-envify` 的版本为 1.0.0,包括所有的子 workspace
(常用于整个 monorepo 某个包确定唯一版本)
**但需要注意的是不存在 `a>b>c` 这种形式**
由于每个包只能确定自己的直接依赖,一个包的一个具体版本在 lockfile 中独一份,所以不存在锁间接依赖,和基于某个子 workspace 维度锁依赖
(否则就会造成多分身的问题,不过 pnpm 中 peer 存在多分身,利用此 Hack 来确定间接依赖版本,可见我这个仓库 [SoonIter/pnpm-peer-trick](https://github.com/SoonIter/pnpm-peer-trick))
```json5
// package.json
"overrides": {
"react>loose-envify>js-tokens": "8.0.0", // ❌
"react>loose-envify": "1.1.0", // ✅
"loose-envify@1.1.0>js-tokens": "8.0.0",
}
```
.pnpmfile.cjs 同理, 不过它比 overrides 更加灵活
> hooks.readPackage(pkg, context): pkg | Promise\
> Allows you to mutate a dependency's package.json after parsing and prior to resolution.
```js
function readPackage(pkg, context) {
if (pkg.name === 'react') {
pkg.dependencies["loose-envify"] = "1.0.0";
}
return pkg;
}
module.exports = {
hooks: {
readPackage,
},
};
```
# 构建层面
依赖层面无法解决子 workspace 维度的锁依赖问题,但是子项目里一个任意规定 resolve 逻辑的 bundler 可以为所欲为
## resolve.alias
一个包只有一个版本
常用于 子项目维度
因此常被用于解决 react 单例,合并版本减小包体
```json5
{
"name": "c",
"dependencies": {
"react": "18.2.0",
"@babel/runtime": "7.21.0"
},
"license": "MIT"
}
```
```js
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
"@babel/runtime": path.resolve(__dirname, 'node_modules', '@babel/runtime'),
"react": path.resolve(__dirname, 'node_modules', 'react'),
},
},
};
```