背景
前段时间,公司碰巧在腾讯的服务器磁盘坏了,碰巧没有备份,碰巧我们的内网npm部署到该机器上了,于是我们的内网npm发布的所有包都丢了,造成了我们有内网依赖的项目在安装依赖包时都出现了问题,下面就是我们这段时间打包的辛路历程。
从上图的打包记录就能看到前端小姐姐当时有多绝望,下面我们就对打包失败的几个主要原因做一下分类。
打包中遇到的问题
- 问题1
报错信息:
kotlin
error An unexpected error occurred: "https://www.npmjs.com/eslint-config-sftc/-/eslint-config-sftc-0.2.15.tgz: Request failed "404 Not Found"".
info If you think this is a bug, please open a bug report with the information provided in "/home/work/.jenkins/workspace/prod_osz_fe__arms/yarn-error.log".
问题原因:内网npm包丢失,在上边的域名下找不到对应版本的依赖包,造成打包报错,注意关键字"error"、"404",此问题在内网npm重新发包后可以解决。
- 问题2
报错信息:
go
error https://www.npmjs.com/eslint-config-sftc/-/eslint-config-sftc-0.2.20.tgz: Integrity check failed for "eslint-config-sftc" (computed integrity doesn't match our records, got "sha512-ZlFJ7NPpHqwVBxwmueftexP/ObrmdLc343rnPS7a0MziKN51qiQcwgF2pFmSoqKYofMIknoaMh+qCvbjG6bAwg== sha1-oNPbeQojpBt40yF3tsS1DcM1c6s=")
问题原因:内网npm重新发布该依赖包的版本后,打包依然报错,看上边信息得知,npm重新发布相同版本的依赖包后,integrity(标准子资源完整性)生成了新的唯一码,而项目中的lock文件仍是资源丢失前的唯一码,安装时校验不一致,删除lock文件中对应包"eslint-config-sftc"的配置,重新打包即可解决
- 问题3
报错信息:
perl
error An unexpected error occurred: "https://registry.npm.taobao.org/rc-util/download/rc-util-5.2.1.tgz?cache=0&sync_timestamp=1599012367543&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Frc-util%2Fdownload%2Frc-util-5.2.1.tgz: certificate has expired".
问题原因 :该问题是由于淘宝镜像证书过期造成在老的镜像地址下载依赖包出现问题,解决方案是将lock文件中 registry.npm.taobao.org域名替换为 registry.npmmirror.com。(尽量避免删除lock文件的解决方式)。同时我们还会遇到registry.nlark.com, 这个域名报错,也是由淘宝源切换造成的,如遇该报错可将 registry.nlark.com 替换为registry.npmmirror.com,即可解决问题。
- 问题4
报错信息:
javascript
NODE_ENV:production BUILD_ENV:test
ERROR Error loading /home/work/.jenkins/workspace/prod_fe__riderh5/vue.config.js:
ERROR SyntaxError: Unexpected token u in JSON at position 0
SyntaxError: Unexpected token u in JSON at position 0
问题原因:我们项目中的打包脚本打印了nodejs和npm的版本(见下图),由于node版本与npm版本不匹配,造成打包脚本报错,一般vue.config.js报错首先考虑node的问题。
下边是Node版本与npm的对应关系,版本不一致可能会造成项目运行或打包报错
官网链接:nodejs.org/zh-cn/about...
NPM相关
介绍完上边具体的打包问题后,下边介绍一下npm的相关内容
NPM常用命令
安装与卸载
-
npm install (npm i) : 安装项目的所有依赖。
sh 复制代码 npm install
-
npm install : 安装指定的包,并将其添加到
dependencies
中。npm install express
-
npm install --save-dev (npm i -D) : 安装指定的包,并将其添加到
devDependencies
中。cssnpm install webpack --save-dev
-
npm install @ : 安装指定版本的包。
cssnpm install lodash@4.17.20
-
npm uninstall : 卸载指定的包,并从
dependencies
或devDependencies
中移除。sh 复制代码 npm uninstall express
-
npm update : 更新项目中所有的依赖到最新的符合
package.json
中定义的版本。sqlnpm update
查看信息
-
npm list (npm ls) : 列出当前项目中已安装的所有包及其依赖关系。
npm list
-
npm list -g --depth=0: 列出全局安装的所有包(不显示子依赖)。
ininpm list -g --depth=0
-
npm info : 查看指定包的详细信息。
npm info express
-
npm outdated: 检查项目中依赖的包是否有新版本。
npm outdated
初始化与配置
-
npm init : 引导创建一个新的
package.json
文件。csharpnpm init
-
npm init -y : 使用默认配置快速创建一个新的
package.json
文件。csharpnpm init -y
-
npm config set : 设置 npm 配置项。
arduinonpm config set registry https://registry.npm.taobao.org
-
npm config get : 获取 npm 配置项的值。
arduinonpm config get registry
-
npm config delete : 删除 npm 配置项。
arduinonpm config delete proxy
-
npm config list: 列出所有 npm 配置项。
arduinonpm config list
脚本
-
npm run xxx : 运行
package.json
中scripts
定义的脚本。arduinonpm run build
-
npm test : 运行
package.json
中scripts
定义的test
脚本。bashnpm test
-
npm start : 运行
package.json
中scripts
定义的start
脚本。sqlnpm start
发布与管理
-
npm publish: 将包发布到 npm 注册表。
npm publish
-
npm unpublish: 从 npm 注册表中移除一个包(需要谨慎使用)。
gonpm unpublish <package>
-
npm login: 登录到 npm 注册表。
npm login
-
npm logout: 注销 npm 注册表。
bashnpm logout
-
npm whoami: 显示当前登录用户的用户名。
bashnpm whoami
其他有用的命令
-
npm cache clean --force: 清理 npm 缓存。
cssnpm cache clean --force
-
npm doctor: 运行检查以帮助诊断和修复常见的 npm 环境问题。
npm doctor
-
npm audit: 检查项目依赖中的安全漏洞。
npm audit
-
npm audit fix: 自动修复项目依赖中的安全漏洞。
matlabnpm audit fix
-
npm version <update_type> : 更新项目的版本号,其中
<update_type>
可以是patch
、minor
或major
。npm version minor
-
npm link: 创建一个符号链接,将当前项目链接到全局 node_modules 文件夹,或将全局安装的包链接到本地项目。
perlnpm link <package>
-
npm ci : 从
package-lock.json
安装依赖,通常用于持续集成环境,确保安装的版本与package-lock.json
一致。npm ci
以上是一些常用的 npm 命令,掌握这些命令可以帮助你更高效地管理项目的依赖和配置,下面介绍一下版本号控制相关内容。
语义化版本规范
版本号由三位数字构成,如1.0.0,分为主版本号、次版本号、修订号。
- 主版本号:当你做了不兼容的 API 修改时递增。
- 次版本号:当你做了向下兼容的功能性新增时递增
- 修订号:当你做了向下兼容的问题修正时递增
举个例子:
- 1.0.0 初始版本。
- 1.1.0 增加了新功能,保持向下兼容。
- 1.1.1 修复了一个 bug,保持向下兼容。
- 2.0.0 引入了不兼容的 API 修改。
而我们安装依赖包时,除了三位版本号,还有一些其他的修饰符用于控制版本:
- 精确版本号 :如
1.2.3
,适合希望完全控制依赖版本 - 波浪号(~) :如
~1.2.3
,匹配1.2.x
系列的最新版本,例如1.2.4
、1.2.5
,但不会安装1.3.0
- 插入符号(^) :如
^1.2.3
,匹配1.x.x
系列的最新版本 - x版本 :如
1.2.x
,类似于~1.2.0
- 主版本号 :如
1
,匹配1.x.x
系列的最新版本,类似^1.0.0
- *号:匹配所有版本,不推荐使用
介绍完npm常用的命令和版本控制后,相信大家对npm有一个大致的了解,最后我们对npm中的lock文件做一个介绍。
LOCK文件简介
我们的业务项目中,基本都会上传一个lock文件到git仓库中,yarn.lcok或者package-lock.json,具体使用什么由打包工具决定,那么lock文件在项目中究竟扮演一个什么角色呢?
LOCK文件的作用
- 描述依赖树的单一表示,以保证团队成员、部署和持续集成安装完全相同的依赖。
- 为用户提供"时光旅行"功能,以返回到 node_modules 的先前状态,而无需提交整个目录
- 通过可读的源控制差异来促进依赖树更改的可见性
- 通过允许 npm 跳过已安装包的重复元数据解析来优化安装过程
LOCK文件的节点
- name: 表示项目名称
- version: 表示项目版本号,一般业务项目迭代上线不会更改版本号,组件库类需要发布npm包的需要更改
- lockfileVersion: 表示lock文件的版本,一般为整数,2版本比1版本多了一个package字段。以下是不同版本之间的区别
- requires: 文件中最外层的 requires: true 是一个布尔值字段,表示 package-lock.json 文件中的依赖关系需要在安装过程中被严格遵循
- dependencies: 字段包含依赖包的完整信息,包括版本、下载 URL 和完整性哈希等。
- packages(v2): 这是一个将包位置映射到包含该包信息的对象的对象。根项目通常列为键为 "",其他所有包列为从根项目文件夹的相对路径
dependencies子字段
- version: 依赖的版本号
- integrity:该资源的标准子资源完整性
- resolved:资源的完整url地址
- dev:如果为true,则此依赖是顶级模块的仅开发依赖或其传递依赖
- optional:如果为true,则此依赖是顶级模块的仅可选依赖或其传递依赖。这对于既是顶级模块的可选依赖又是顶级模块的非可选依赖的传递依赖都是 false
- bundled:如果为真,则这是捆绑依赖,将由父模块安装
上述配置我们看到一个lockfileVersion字段,不同npm版本对应不同的lock文件版本,下图是两个项目中不同版本的lock文件
那么不同版本的lock文件,区别在哪呢:
-
依赖结构:lockfileVersion: 1 的 package-lock.json 文件中,依赖结构为层级结构,子依赖嵌套在父依赖中;lockfileVersion: 2 的 package-lock.json 文件中,依赖结构为平铺结构,所有依赖都列在 packages 节点中,并通过相对路径来表示。
-
依赖关系:在 lockfileVersion: 1 中,依赖关系通过 requires 字段表示;在 lockfileVersion: 2 中,依赖关系通过 dependencies 节点表示,且更加详细和扁平化。
-
性能优化:lockfileVersion: 2 提供了更详细的信息,减少了对 package.json 文件和 node_modules 的依赖,提升了性能。
-
兼容性:lockfileVersion: 2 兼容 lockfileVersion: 1,但 lockfileVersion: 3 则不具有向后兼容性,主要用于隐藏锁定文件。
总结来说,2版本比1版本性能更好,查找依赖速度更快,并且可以兼容1版本对应的npm,推荐使用。
今天想到的大概就是这些内容,希望大家可以通过以上的案例和文档,快速的解决工作中遇到的打包问题,感谢阅读。