你可能不知道的但天天接触的 npm install

名词 解释
MR merge request
oci orange ci 腾讯内部使用的一款CI服务

故事是这样的

某天我高高兴兴提了 MR 后,开始干其它活儿坐等 oci 流水线跑完,结果没过一会儿收到企微推送说流水线报错了,从错误日志中立马意识到是 npm 包版本问题引起的。本以为高枕无忧的我顿时菊花一紧,咋肥四?

背景介绍

简单介绍一下这次 MR 我干了什么事情。
由于业务需要,在一个规模比较大的仓库里,新增了两个 devDenpendencies,一个是 commander,另一个是 @tencent/alloyperf(下文简称 alloyperf)。

这里有一个小插曲,由于 alloyperf 近期做了一些优化和升级,于是在开发将近结束的时间点,在某一次合并主干代码操作后,发现程序报错了。
当然报的不是什么毁灭性的错误,而是 ts 类型错误,大致就是旧版本的包有 export 某个 interface,我使用了这个 interface,结果在新版本中居然没有 export 了,导致了报错。
要解决这个问题,肯定是可以解决的,但是我并不想为了这点小事花费时间,也许解决问题只要5分钟,但是解决问题后的善后工作,比如测试,跑流水线,操作过程中程序的等待时间等等,加起来可能就是50分钟。
所以其实有个最简单的方法,就是什么都不要变,锁定最初使用的包版本即可。

解决问题

alloyperf 的现状是这样的:
"@tencent/alloyperf": "^1.6.8"
这里其实已经表明,在装包时是会安装到 1.6.8 往上的版本的。

关于 npm 包版本规范 semantic 不会在本文展开,自行阅读 docs.npmjs.com/about-seman…
简单说就是:
@1.0.0 => must be 1.0.0
^1.0.0 => maybe 1.3.6
~1.0.0 => maybe 1.0.12

如何查看目前安装的版本号?
在 node_modules/@tencent/alloyperf/package.json 的 version 字段可查看。

检查发现果然装的是 1.7.6 版本。
简单,那就装回 1.6.8 版本吧!
npm i @tencent/alloyperf@1.6.8 -D

结果发现 package.json 显示的包版本号依然是
"@tencent/alloyperf": "^1.6.8"
与我期待显示的“1.6.8”不同,于是我再次检查所装包版本,发现正确地装回了 1.6.8 版本,package-lock.json 文件也正确地同步更新。因此可得出结论:

通过命令 npm i @ 精确安装某版本包时,能够正确地安装指定版本包,并更新 package.lock.json,但在 package.json 文件内显示的包版本号,是“^”

包确实是安装回来了,但是 package.json 文件却不能在执行命令结束后,正确显示版本号。那后续的同学执行安装命令时,或是流水线安装包时,不就又装回了最新的 1.7.6 版本了吗?
让我们来做几个测试!

以下每个用例的前置条件:
package.json 显示包版本号为”^1.6.8″
package-lock.json 显示包版本号为”1.6.8″
包实际版本为 “1.6.8”

  • 在本地再次执行 npm i

结果:包版本不变。

  • 删除 package-lock.json,执行 npm i

结果:生成了 package-lock.json 文件,包版本不变。

  • 删除包,执行 npm i

结果:包版本不变。

  • 删除 package-lock.json,删除包,执行 npm i

结果:包和 lock 文件的包信息升级到了最新的 1.7.6 版本,package.json 显示的包版本号不变。

可得出以下结论:

执行 npm i 时
如果有 package-lock.json 文件,会按照 lock 文件的包版本号信息进行安装
如果没有 package-lock.json 文件

  • 当本地安装包时,执行后只是会生成 package-lock.json 文件
  • 当本地没有安装包时,会安装包的最新版本

npm 文档相关描述
km1.png

回到问题,我现在希望通过执行单独安装 alloyperf 命令,达到三个效果:

  • package.json 显示的包版本号,为命令中指定的安装版本号
  • package-lock.json 显示的包版本信息同⬆️要求
  • 实际安装包版本同⬆️

我们执行以下两个命令看看:

npm i @tencent/alloyperf -D
包会安装到最新版本,显然不符合我的期望。

npm i @tencent/alloyperf@1.6.8 -D
如上文所提到的那样,除了 package.json 显示包版本号为“^1.6.8”以外,其它均符合期望。

npm 文档相关描述
km2.png

那么 npm 是否有提供解决上述问题的方法呢?
答案肯定是有的!

在 npm 的文档
docs.npmjs.com/cli/v7/comm… 内有提到:
km3.png
翻译一下就是,使用这个参数后,在保存依赖时,将以命令中提供的精确版本号,代替 npm 的默认行为。

所以安装命令就应该修改为这样:
npm i @tencent/alloyperf -D -E

我留意到文档 -E 参数描述的末尾有提到 npm's default semver range operator,那么 npm 的这个默认行为是否能够被某种方式更改呢?
可以!

在 npm 的文档 docs.npmjs.com/cli/v7/usin… 内有提到:
km4.png
也就是说,在每次安装指定包时,并赋予了 -S 或是 -D 参数,npm 的默认行为是会在将包版本号登记进 package.json 时,添加“^”前缀。这个默认前缀是支持更改的。

至此问题解决!

结语

关于 npm 的使用,平常几乎只会在遇到需要新增依赖时,才 npm install 一下,对于 npm install 的过程做了什么事情,很多人可能还是从来没了解过的,建议大家找相关资料好好了解一下,我认为这对于现代前端开发来说是一个必要知识点。
就像 javascript 被很多人吐槽这个那个的坑,但我们仍然每天都在写这个语言,还有后来的 ES6/7/8/9,也有 typescript 等等。就是因为我们深刻了解了 js,才有后来的蓬勃发展。
不说了,我也要补补课了!

花絮

在调试过程中发现 npm 返回的日志中有一行命令
npm fund
印象中经常会在日志中看到,所以去搜了一下,它的作用大致是这样的
列出所有希望别人捐赠 money 的包的列表
俗一点说就是,假如你写了个开源库,希望路人行行好给点钱奖励你的付出,你就可以在 package.json 稍作修改,一旦有项目使用到你的成果,他们就有机会看到你的需求,心情好说不定就给你打钱了!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享