semver 语义化版本控制
首先,快速的带大家回顾一下 semver 语义化版本控制
我们的 npm 模块都是严格遵循这套版本控制的
格式为 [major, minor, patch]
例如 react@18.2.0
大版本就是 18, 次版本为 2,补丁版本则为 0
大版本表示有 breakChange ,可能会有不向前兼容的 api
次版本则为一些小改动
补丁版本为一些 bug 的修复
次版本和补丁版都是向前兼容的版本
除此之外,在 package.json
中我们还可以看到一些符号
json
"dependencies": {
// ^ 表示允许更新次版本和补丁版本,
// 例如可以更新到 18.2.1 / 18.3.0
// 但是不会更新到 19.0.0
"react": "^18.2.0",
// ~ 表示允许更新补丁版本,
// 例如可以更新到 18.2.1
// 但是不会更新到 18.3.0 / 19.0.0
"react-dom": "~18.2.0",
// 不加任何符号 表示准确的匹配某个版本
"lodash": "4.17.21"
},
现在回到正题 介绍一下 package.json 中的 overrides
/ resolution
字段
场景一:安装依赖冲突
我们初始化一个项目
yarn create vite npm --template react-ts
先用 npm 来介绍,后面针对 yarn 补充一些不同的地方
除去一些无用的依赖,我们得到一个最小的 package.json
json
{
"name": "npm",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.2.2",
"vite": "^5.0.8"
}
}
然后我们引入一个用于 json 可视化的库
npm install react-json-view
这个时候就会得到一个报错
查看报错原因或者 react-json-view
的 package.json 的 peerDependencies
json
"peerDependencies": {
"react": "^17.0.0 || ^16.3.0 || ^15.5.4",
"react-dom": "^17.0.0 || ^16.3.0 || ^15.5.4"
}
可以看到 我们项目的直接依赖 react 的版本是 18.2.0 不满足 react-json-view 中需要的 react 的版本
这个时候就可以引出 overrides
了
我们在 package.json
中加入一个新的字段 overrides
json
"overrides": {
// 表示只覆盖 react-json-view 这个项目下的依赖
"react-json-view": {
// $ 表示跟随本项目下的react版本,即^18.2.0
"react": "$react",
// 当然也可以直接指定对应的重写版本 (推荐上述写法)
"react-dom": "^18.2.0"
}
}
然后再运行 npm install react-json-view 就可以看到依赖被成功的安装了
运行 npm ls react-dom
查看 react-dom 在项目中依赖关系
可以看到 react-json-view 下的 react-dom 版本已经被重写了
场景二:解决一些 security bug
第二种场景则是,例如你维护了一个时间比较久的项目,
突然在某次上线前的 security scan 中 发现了一些第三方模块的漏洞,需要升级这些模块来 fix
其中,有的可能是项目的直接依赖,有的则是第三方模块的子依赖,甚至可能是很深的子依赖
这个时候,你也需要用到 overrides
来重写项目中的依赖关系
当然前提是,你得知道重写后不会破坏项目的运行
还是这个项目我们运行
npm ls semver
我们可以看到 semver 在项目中有两个并存的版本 6.x 的 和 7.x 的
例如,如果有一天在安全扫描的时候,我们被告诉 6.x 的这个版本有安全问题需要升级到最新的版本
这个时候也可以通过 overrides
来实现
json
"overrides": {
"react-json-view": {
"react": "$react",
"react-dom": "$react-dom"
},
"semver": "^7.5.4"
}
重新安装依赖,可以看到项目中所有用到 semver 的地方都被替换成了我们指定的版本
当然启动项目也是正常的
补充一些 yarn 的区别
yarn 和 npm 不同的地方在于
yarn 中重写依赖的字段不是 overrides 而是 resolutions
同时查看依赖关系的命令为 yarn list --pattern react-dom
等价于 npm ls react-dom
overrides 中可以嵌套的书写,重写某个特定模块下的子依赖 例如
json
"overrides": {
"react-json-view": {
"react": "$react",
"react-dom": "$react-dom"
},
}
但是在 yarn 下 只能写成
json
"resolutions": {
"react": "$react",
"react-dom": "$react-dom"
}