很多时候我们的项目换个电脑就语法错误、运行报错、打包失败可能都是因为使用了不同的node版本导致的兼容性问题。package-lock.json 的冲突也有可能是node版本不一致导致的,本文就从解决package-lock.json 开始说起。
为什么package-lock 频繁冲突
多人合作时,为什么package-lock 频繁冲突?如下图
这个时候就有小伙伴说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 dev 、 npm 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 lodash时 engines + engine-strict 无效,npm 钩子preinstall也无法拦截。可以使用git hooks工具 husky/pre-commit 时校验来禁止提交可能导致冲突的 package-lock.json 文件。npm run dev、npm run build 报错也可能时node版本兼容问题。可以在 npm 钩子 predev、prebuild 时校验node版本。
如有不足,还请指教。欢迎讨论交流。