--ignore-engines是让报错消失,不是让问题消失;装得下不等于跑得起来。
用 Node 16 装一个依赖了新版工具链的项目,yarn 直接中断:
error glob@10.4.3: The engine "node" is incompatible with this module. Expected version ">=18". Got "16.20.2"
error Found incompatible module.
glob@10 的 package.json 里写了 "engines": { "node": ">=18" },yarn 1 默认把这条当硬约束,不满足就拒绝安装。npm 只警告不拦截,pnpm 视 engine-strict 配置而定,所以同一个项目换包管理器表现不一样。
| 方式 | 做法 | 适用场景 | 风险 |
|---|---|---|---|
| 升级 Node | nvm install 20 && nvm use 20 | 项目是新的、自己说了算 | 几乎无风险,首选 |
| 临时绕过检查 | yarn install --ignore-engines | 只是某个间接依赖标了高版本,实际 API 兼容 | 运行时报错更难排查 |
| 锁定依赖版本 | 把该包降到支持当前 Node 的版本 | 老项目短期不能升 Node | 可能触发其他包的 peer 冲突 |
先绕过检查把依赖装上,是运维排查时的常用手段:
yarn install --ignore-engines
# 或只装单个包时忽略
yarn add xxx --ignore-engines
npm 对应的是 npm install --engine-strict=false(npm 默认就是 false,通常不需要加),pnpm 对应 pnpm install --config.engine-strict=false。
engines 不是装饰性字段。glob@10 声明 >=18 是因为它用了 Node 18 才稳定的 API(如 fs.glob、内置 test runner 相关能力),在 16 上装成功了,运行到那条分支就抛 TypeError: xxx is not a function。这类报错发生在构建或运行时,堆栈指向第三方库内部,比安装期的一句 incompatible module 难定位得多。
判断能不能绕过的实操方法:看报错里那个包是不是只在构建期用(如 glob、esbuild、rollup)。构建期工具版本不匹配通常立刻暴露;运行期依赖(数据库驱动、加密库)出现版本不符,基本一定会炸。
单机绕过之后,CI 和同事的机器会重复踩。三件事能把版本钉住:
# 1. 项目根目录声明期望版本
echo "20" > .nvmrc # nvm / fnm 自动读取
# 或 package.json 里写死
# "engines": { "node": ">=18 <21" }
// 2. package.json 里的 engines 只做提示,配合 .npmrc 才生效
{
"engines": { "node": ">=18" }
}
# 3. 对间接依赖强制指定版本(yarn 1)
yarn add -D resolutions
// package.json
{
"resolutions": {
"glob": "^10.4.3"
}
}
pnpm 用 ,npm 8+ 用 ,写法一致。
pnpm.overridesoverrides很多人以为报错的是自己直接装的包。实际上 glob@10 通常是 webpack、eslint、npm 自身这类工具的传递依赖,yarn why glob 才能看到是谁拖进来的。
很多人以为换了 Node 版本就万事大吉。项目里可能同时有 .nvmrc、Dockerfile 的 FROM node:16、CI 的 node-version: 16 三处版本声明,只改本地会出现「本地能跑、流水线报错」。
很多人以为 --ignore-engines 只影响安装。yarn 1 会把它写进 .yarnrc 后长期生效,之后所有项目的引擎检查都失效了,等于把安全网撤掉。
node -v # 当前版本
cat .nvmrc # 项目期望版本
yarn why glob # 谁引入了这个包
yarn info glob engines # 这个包声明了什么
grep -r "node:" Dockerfile .github/workflows 2>/dev/null # 其他地方的版本声明