前言
最近在项目中,遇到node_modules方面的问题比较多,积累了一些异常事故的处理经验,与大家分享一下。有些问题当时让我感到很棘手,花费了很长时间,最后才试出正解。现在我们进入今天的正题:
事故一 The engine "node" is incompatible with this module
如何解决?
项目背景是这样的, 我们是乙方公司,在外网开发功能, 开发好了之后把代码全量同步交付给甲方公司,甲方公司在他们的内网完成打包构建部署。基于这样的协作模式, 因此没有把在外网环境下安装完项目依赖包后生成的yarn.lock文件上传到git仓库,而是设置成了git忽略文件。因为如果把yarn.lock文件上传到代码仓库,甲方公司同步我们的仓库代码后,在他们的内网环境,每次执行Jenkins自动打包部署任务时,即便使用下面的命令配置了yarn的私有镜像源,
bash
yarn config set registry npm私有源地址
执行yarn安装依赖包的时候,读取的安装包下载地址还是外网地址,因为yarn读取依赖包下载地址时,优先会读取yarn.lock文件中写入的安装包下载地址而非配置的yarn私有镜像源地址。这会导致依赖包无法在内网环境安装。
此外,还要锁定项目中依赖包的版本。为了锁定项目中npm包的依赖版本, 我把package.json中的dependencies
和devDependencies
两部分依赖包版本中的~
和^
都去掉了,就像下面这样,锁死直接依赖包版本。
锁死生产依赖和开发依赖版本后,一直都岁月静好, 直到有一天翻车了。突然冒出一个依赖包和node版本不兼容的错误,导致打包构建失败,错误如下:
在npm上查看了一下@yarnpkg/parsers@3.0.0-rc.49包的package.json 文件中的engines
配置,找到了问题所在:因为项目中当前使用的node版本是16.13.2,而这个包要求的node版本要大于v18.12.0,所以引起安装出错。又看了一下本地项目中打包构建正常的@yarnpkg/parsers
包版本,为3.0.0-rc.48.1
, 可以看出,Jenkins每次打包构建安装依赖时,@yarnpkg/parsers
的版本会自动升级, 说明在package.json无法锁定依赖的间接依赖包版本,只能锁住直接依赖版本。
在网上查询试验一番之后, 找到了正解.可以在package.json的resolutions
字段中声明间接依赖包的版本。这种方法虽然解决了本次打包出现的问题,但要想杜绝再出现此类问题,就得把内网环境生成的yarn.lock文件添加到版本库。从.gitignore
文件中移除对yarn.lock
设置忽略。同时把外网环境下安装项目依赖包时生成的yarn.lock文件重新改个名字,也提交到代码仓库。在外网安装依赖的时候,把内网的yarn.lock和外网的yarn.lock文件名互换一下,安装完再恢复。这样内外网的yarn.lock文件就能同时并存于代码仓库。
json
"resolutions": {
"@yarnpkg/parsers": "3.0.0-rc.48.1"
}
事故二 npm ERR! gyp ERR!错误如何解决?
这个问题是由一个tree-sitter-json
的npm包引起的,tree-sitter-json
用到了node-gpy
,node-gyp
的主要作用是编译原生 C++ 模块,解决模块的跨平台问题,node-gyp
是社区对google gyp
工具的封装,而 gyp
是用 python
写的,所以运行时需要python
环境, 于是按照报错提示,去Python官网下载安装最新的windows python版本。
再次运行安装指令,又报如下错误,提示要安装Visual Studio
。
去官网下载 Visual Studio
最新的安装包 ,安装时勾选上使用C++ 的桌面开发选项
进行安装。
安装完Visual Studio
之后,再次运行又报msvs_version版本不匹配
这个错误是说npm 指定的编译器版本和系统中的Visual Studio
版本对不上, 修改npm指定的Visual Studio
版本,与操作系统实际安装的Visual Studio
版本保持一致。
bash
npm config set msvs_version 2022
经过一波三折之后,终于在项目下执行yarn
指令不报错了。
事故三 项目启动后,控制台出现大量的Vite报错信息, 项目无法启动,如何解决?
报错信息为[vite] Failed to load source map for /node_modules/.vite/deps/ant-design-vue_es-xxx.js.map
, 如何解决?
看提示是Vite启动项目的时候加载ant-design-vue缓存的map文件失败了,查看了一下项目下的node_modules/.vite/deps文件夹,发现什么文件也没有,加载失败很正常。令人感到奇怪的是,用vite --force
命令重新启动项目,强制重新生成依赖缓存文件,也不生成依赖缓存文件。在网上查找了半天,只看到有人描述这个问题,可是没有解决方案。最后抱着死马当活马医的心态,尝试着升级了一下vite
,vite-plugin-style-import
,ant-design-vue
,问题得到解决。
vite-plugin-style-import
升级前后按需加载ant-design-vue
组件样式的配置差异:
- v1.4.1版本写法
js
import styleImport from "vite-plugin-style-import";
// 按需加载样式文件
styleImport({
libs: [
{
libraryName: "ant-design-vue",
esModule: true,
resolveStyle: (name) => {
return `ant-design-vue/es/${name}/style/index`;
},
},
],
});
- v2.0.0版本写法
js
// 按需加载UI组件样式,vite 自带按需加载仅针对js
import { createStyleImportPlugin, AndDesignVueResolve } from "vite-plugin-style-import";
// 按需加载样式文件
createStyleImportPlugin({
resolves: [AndDesignVueResolve()],
});
事故四 stylelint报错Stylelint: Invalid value "consecutive-duplicates-with-different-syntaxes" for option "ignore" of rule "declaration-block-no-duplicate-properties"
的解决方法?
提示consecutive-duplicates-with-different-syntaxes
这个属性值是无效的,查看了一下stylelint的官方文档,发现这是stylelint-v15.5.0才有的属性,而项目中使用的stylelint版本是14.3.0, 肯定没有这个属性。
stylelint使用了stylelint-config-recommended,在node_modules/stylelint-config-recommended/index.js
找到报错的配置。
这说明stylelint-config-recommended
包的版本太高了,与项目中安装stylelint包版本不匹配, 那么解决这个问题的思路就很清晰了。
要么升级stylelint
到更高版本,要么降低stylelint-config-recommended
的版本, 最简单的改法,就是在.stylelintrc.js中覆盖这条规则。
js
rules: {
'declaration-block-no-duplicate-properties': [true],
}
事故五 yarn build 构建时报错 - Error EPERM operation not permitted,xxx
如何解决?
最后查明,这是因为文件被别的应用占用导致的。因为使用cosbrowser
软件上传部署包时,突然发现有个地方没改好,还得改改。 于是改好之后,重新打包,而这时上一次的打包文件还在cosbrowser
软件中处于上传状态,被占用着,所有重新打包的时候,无法覆盖同名文件。抛出上面的错误,只要关闭占用dist/assets目录下文件的cosbrowser
软件,打包就正常了。
事故六 Browserslist: caniuse-lite is outdated. Please run next command npm update
解决方案?
提示说caniuse-lite
包过时了,需要执行一下npm update
命令,但我们不能直接执行npm update
,因为这会让项目中所有的依赖包全部更新,建议先删除这两个依赖包
bash
yarn remove caniuse-lite browserslist
再安装最新的依赖包,比直接使用npm update命令只更新这两个安装包更快。
bash
yarn add -D caniuse-lite browserslist
最后
在实际项目中遇到的npm包方面的问题,不止这六次事故,只不过这六次事故被我记录下来了,其它的我当时解决了没有做记录,而且有些在网上查询不到答案,花了蛮久的时间才解决的。现在觉得当时的苦头白吃了,因为没有相应的经验积累下来。好记性不如烂笔头,花了很久才解决的问题,不管问题难易,对自己而言,都有记录的价值。不要怕麻烦,怕花时间。若是怕麻烦,后面还会有更大的麻烦等着你,为了以后的路走得平坦一些,牺牲点当下的娱乐时间,辛苦做一下记录也是值得的。