近期接手了一个新项目,clone下来发现
readme无迹可循,node 版本等信息,只能口口相传,强依赖于上一个开发者- 项目中有 npm, yan, pnpm 相关的配置,却无法知道明确应该使用那个包管理工具
于是开始致力于寻找解决之法
1. 指定 node 版本
1.1. 约束
问题:如果开发者任意使用了某个版本的 node,显然是不符合预期的,所以我们需要添加约束,来尽可能早的暴露错误
目的:开发者可以从项目配置获取到 node 版本信息,以及使用了不符合的 node 版本时warn 或 error
步骤一:最基础约束:package.json → engines
配置方式:
{
"engines": {
"node": ">=18 <21"
}
}
实际效果:
- npm / pnpm / yarn 会检查
不一样的包管理工具,或同一包管理工具的不同版本,对应行为的说法多种多样,最好自己试一下,下面贴我试下来的结果:
- npm 10.9.2
- pnpm 9.5.0
- yarn 1.22.22
npm: warn
pnpm: warn
yarn: error
步骤二:最基础约束基础上添加engine-strict=true
engine-strict=true
npm: error
pnpm: error
yarn: error (原本也是)
步骤三:脚本约束(最终防线 可选)
const [major] = process.versions.node.split('.').map(Number)
if (major < 18 || major >= 21) {
console.error(
`❌ Node.js version ${process.versions.node} is not supported.\n` +
`Required: >=18 <21`
)
process.exit(1)
}
{
"scripts":{
"preinstall": "node scripts/check-node.js"
}
}
1.2. node 版本切换辅助
目的:进入项目实现 node 版本自动切换,或简化手动版本切换
方案一:nvm + .nvmrc (手动)
1️⃣ 在项目根目录新建 .nvmrc
22.16.0
2️⃣ 进入项目执行 nvm use
开发者需要提前安装
nvm(macOS / Linux)- Windows 需要
nvm-windows
方案二:Volta (自动)
1️⃣ 在项目中 pin node
volta pin node@22.16.0
# 包管理工具一起固定
# volta pin pnpm@9.12.2 # 或 yarn@1.22.19 / npm@10.8.3
生成如下内容,会添加在 package.josn文件中
{
"volta": {
"node": "18.19.0"
}
}
2️⃣ 自动切换 node
不需要手动切换,进入项目后,volta 会在第一次用到 node 时自动切换为目标 node 版本(如果没有目标版本,会自动下载),进入项目 node -v可验证
开发者需要提前安装
- Volta
注意⚠️:现在 volta 不支持 uninstall node
原因:Volta 把 Node 当成“基础设施”,官方不支持、也不推荐卸载 node
偏方:自己找到文件夹的位置
~/.volta/tools/image/node/删掉
2. 指定包管理工具
包管理工具 packageManager (PM)
当看见项目中关于npm,pnpm,yarn包管理工具的配置都存在时,我一脸蒙,不知道应该用哪一个包管理工具,此时明确指定包管理工具才是预期,那么如何指定呢?
2.1. 约束
目的:开发者可以从项目配置获取到可以使用哪个包管理工具,以及使用了不符合的 node 版本时 error
步骤一:package.json -> packageManager(声明 软提醒)
比如指定 pnpm
{
"packageManager": "pnpm@10.18.3"
}
步骤二: only-allow(强制)
npx only-allow pnpm,npx only-allow npm,npx only-allow yarn
{
"preinstall": "npx only-allow pnpm"
}
如果有其他脚本,建议把这个放在前面 npx only-allow pnpm && node scripts/check-node.js,此时再用pnpm外的包管理工具可就不行了:
步骤三:脚本约束(最终防线 可选)
const userAgent = process.env.npm_config_user_agent || '';
if (!userAgent.includes('pnpm')) {
console.error('❌ 请使用 pnpm 安装依赖');
console.error('💡 运行: corepack enable && pnpm install');
process.exit(1);
}
{
"scripts":{
"preinstall": "npx only-allow pnpm && node scripts/check-node.js"
}
}
暂时用"preinstall": "node scripts/check-node.js"查看报错:
2.2. 包管理工具切换辅助 ❌
我们没法辅助开发者切换npm/ pnpm /yarn,因为他们本来就不是项目级工具,而是系统级工具,开发者想用哪个用哪个(他尽管用,我们在约束环节已经拦截)
3. 指定包管理工具版本
3.1. 约束
3.1.1. npm 专有约束
1️⃣ package.json#npm
{
"engines": {
"node": ">=18 <21",
"npm": "11.7.0"
},
}
2️⃣ .npmrc
engine-strict=true
3.1.2. pnpm 专有约束
1️⃣ package.json (声明)
{
"engines": {
"node": ">=18 <21",
"pnpm": "9.1.1"
},
}
3.1.3. 共享约束:脚本约束
三个PM都可以用的约束,以 pnpm@10.28.2 为例
import * as semver from 'semver';
import { execSync } from 'child_process';
const REQUIRED = '10.28.2';
const current = execSync('pnpm -v').toString().trim();
if (!semver.eq(current, REQUIRED)) {
console.error(`
❌ pnpm 版本不符合要求
当前版本: ${current}
要求版本: ${REQUIRED}
`);
process.exit(1);
}
3.2. 包管理工具版本辅助切换
3.2.1. pnpm 自身的版本管理
{
"packageManager": "pnpm@10.28.0",
}
pnpm 触发时,检查 packageManager字段,如果发现不一致会尝试下载并切换到packageManager指定的版本
3.2.2. yarn 依赖 packageManager+corepack
1️⃣ corepack enable
Node.js 版本 ≥ 16.9 <25 自带corepack,没有则先安装corepack
2️⃣ 提供PM信息
{
"packageManager": "yarn@1.22.20",
}
3️⃣ 自动切换
使用PM时,corepack会读packageManager如果发现版本不一致,触发自动下载
关于
corepack可以解决用什么PM(packageManager 包管理工具)?什么PM 版本?我持怀疑态度,理由如下
corepack出现的初衷本来就是为了统一PM的版本,而不是统一用户哪一个包版本工具,那都有人说它可以,那尝试一下硬着头皮用。发现用它来指定PM需要:
- 开发者本地存在
corepack或Node.js 版本 ≥ 16.9 <25(自带,也不完全自带,如果是 volta下载的,就不会带),且需要corepack enable- 无论 packageManager 配置了什么,都不限制
npm install- 只能限制
corepack下载的包版本工具,但哪个前端开发笔记本不安装几个包管理工具?发现用它来指PM版本也存在问题:
Corepack 不管理 npm, 配置了
npm@10.25.0但是任何版本的npm都会直接执行,不会下载指定版本结论:❌ 多少有些不可靠,现在能想到的应用场景就只有辅助 yarn 版本切换了
绕死我了!🙂↔️🙂↔️🙂↔️