如何限制项目使用指定的node版本

8,605 阅读3分钟

很多时候我们的项目换个电脑就语法错误、运行报错、打包失败可能都是因为使用了不同的node版本导致的兼容性问题。package-lock.json 的冲突也有可能是node版本不一致导致的,本文就从解决package-lock.json 开始说起。

为什么package-lock 频繁冲突

多人合作时,为什么package-lock 频繁冲突?如下图

image.png

这个时候就有小伙伴说package-lock.json 没用,忽略掉吧。

当然,我坚决不同意。因为package.json 与 package-lock.json 的关系 - 掘金 (juejin.cn)

原来是node版本不统一,node预置的npm版本不一样,生成的package-lock.json的 lockfileVersion 不一致。于是我告诉小伙伴npm 版本不一致,你需要升级一下。小伙伴准备执行如下命令,被我制止了。

npm i -g npm # 不要这么干,应该升级node版本,使用node默认绑定的npm

于是小伙伴准备去node 官网下载个新版本 node,然后又被我制止了。先安装个nvm吧,我们项目会越来越多,每个项目可能使用不同的node版本。

虽然大家知道问题了,但还是避免不了问题的出现。因为有的小伙伴nvm迟迟不安装,就一个node版本,还有的忘了切换node版本。每次都会生成新的package-lock.json,导致冲突。

该放大招了

如何限制npm install使用的node版本

package.json 添加字段 engines

// package.json
"engines": {
    "node": "16.13.0",
    "npm": "8.1.0"
}

这么做npm并不管用,使用yarn的时候才可以限制。我们团队都使用npm,本项目也禁止使用其他包管理工具,为此也做了限制。

// package.json
{
    "scripts": {
        "preinstall": "npx only-allow npm" // 只能使用npm 安装包
    }
}

原来 engines 只是建议,默认不开启严格版本校验,只会给出提示,需要手动开启严格模式。在根目录下 .npmrc 添加 engine-strict = true

# .npmrc
engine-strict = true

这下 npm install 的时候就会报错了。

192:smart-community user$ npm i
npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for smart-community@1.0.0: wanted: {"node":"~16.13.0","npm":"~8.1.0"} (current: {"node":"14.18.1","npm":"6.14.15"})
npm ERR! notsup Not compatible with your version of node/npm: smart-community@1.0.0
npm ERR! notsup Not compatible with your version of node/npm: smart-community@1.0.0
npm ERR! notsup Required: {"node":"~16.13.0","npm":"~8.1.0"}
npm ERR! notsup Actual:   {"npm":"6.14.15","node":"14.18.1"}

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/user/.npm/_logs/2022-08-14T07_29_16_968Z-debug.log

根目录放一个.nvmrc切换node版本更方便,nvm use 就可以切换,不需要后面加版本号

# .nvmrc
v16.17.0

没过多久又发现 package-lock.json冲突了

原来engine-strict 只能限制 npm install ,如果下载指定的npm 包,还是可以下载的,例如

npm install lodash --save

这样执行是不会校验npm版本的,目前还没有找到好的办法去限制,npm 的 preinstall 钩子也不会执行。

禁止提交冲突的package-logo.json

于是换种思路, 让冲突代码提交不上去。冲突主要是因为lockfileVersion版本不一致导致的。如果lockfileVersion一致,至少不会对别人的代码和环境造成影响。 在提交之前判断lockfileVersion是否一致。如果不一致,就终止进程,禁止提交代码,并给出切换版本重新npm install 的提示。

.husky/pre-commit 添加如下代码

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

PATH=$PATH:/usr/local/bin:/usr/local/sbin

npm run check:lockfile # 新增校验package-lock.json 中lockfileVersion字段
npm run check:dependencies
npx lint-staged

npm 新增script

{
    "script": {
        ...,
        "check:lockfile": "node ./misc/checkLockfile"
    }
}

项目新增js 文件

// /misc/checkLockfile.js
const { lockfileVersion } = require('../package-lock.json')
const { engines } = require('../package')

if (lockfileVersion !== 2) { // 判断lockfileVersion版本,不是2就终止进程
  console.error(`Required node version ${engines.node} and npm version ${engines.npm}, And then please retry npm install.`)
  process.exit(1)
}

这下舒服了,package-lock.json 冲突的问题再没有出现。


限制运行时node版本

用限制node版本的方式解决了package-lock.json 冲突问题。真正运行项目或者打包项目时使用的node版本又该如何限制。怎么保证每个环境运行的都是同一个node版本。

为什么要保证每个环境运行的都是同一个node版本?

经常会遇到,有的小伙伴 npm run dev 启动不了项目了。在服务器上运行 npm run build 报语法错误了,本地尝试却是好好的。很多时候都是因为node版本不兼容。

在package.json 中添加npm scripts 钩子。可以在运行 npm run devnpm run build 之前去执行

// package.json
{
    "script": {
        ...,
        "predev": "npm run check:node", // 开发时校验
        "prebuild": "npm run check:node" // 打包时校验
        "check:node": "node ./misc/checkNode",
    }
}

校验当前node版本与项目要求的node版本是否匹配。如果不匹配,打印错误提示信息,终止进程。

// misc/checkNode.js
const { engines } = require('../package')

let semver = null
try {
  semver = require('semver') // 校验版本号的一个工具
} catch (error) {}

const version = engines.node
if (semver && (!semver.satisfies(process.version, version))) {
  console.error(`Required node version ${version}, got: ${process.version}.`)
  process.exit(1)
}
if (!semver && (process.version !== version)) {
  console.error(`Required node version ${version} and npm version ${engines.npm}, got: ${process.version}.`)
  process.exit(1)
}

---- 2023/4/23 更新 如果使用pnpm包管理,默认不会执行 npm 的pre、post 钩子,开启方式 .npmrc 中添加 enable-pre-post-scripts=true

总结:package-lock.json 频繁冲突有可能是 npm install 时使用的node版本不一致导致的。engines + engine-strict 可以限制 npm install 时的node版本。下载指定包如 npm install lodashengines + engine-strict 无效,npm 钩子preinstall也无法拦截。可以使用git hooks工具 husky/pre-commit 时校验来禁止提交可能导致冲突的 package-lock.json 文件。npm run devnpm run build 报错也可能时node版本兼容问题。可以在 npm 钩子 predevprebuild 时校验node版本。


如有不足,还请指教。欢迎讨论交流。