1

package-lock.json的前世今生

 2 years ago
source link: https://www.zoucz.com/blog/2020/05/31/f23b2980-a30c-11ea-90b5-eb40e9720ed0/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

首先说npm,从上学到工作,写代码这些年来,接触过java、c#、js(nodejs)、python、c++等多种语言,这些语言依赖包管理各式各样,至今感到最丝滑的还是nodejs的包管理机制。 我要说话

nodejs的包管理工具就是大家最常用的npm了,npm本身是依托于nodejs运行的,而安装nodejs的时候一般也会附带npm工具,nodejs版本和附带npm版本的列表见:nodejs历代版本。为什么要提及版本呢? 我要说话

本文的主人公,在历代版本中的变化是神鬼莫测,各种两头不讨好,活像了各位开发哥被产品魔改需求的样子,也像我们改bug时堵东漏西的样子… 我要说话

版本锁定——设计对工程的妥协

npm的包管理使用起来确实是简单方便,在nodejs社区蓬勃发展的过程中,海量的模块被发布到了npm仓库中,大家写代码的时候各种轮子需要自己造的越来越少,大部分都可以在npmjs.com上搜索,找个最popular的拿来用。 我要说话

时间长了,大家发现,一个项目中手撸的代码没多少,依赖的模块倒是一堆一堆的,这些模块五花八门,维护者来自五湖四海,靠谱的、不靠谱的都有。 某几次下载代码npm install,发现跑不起来,经过一番排查,发现不是自己手撸代码的BUG,而是某个依赖包出BUG了,于是怒上心头,开始问候作者。其实呢,这种情况也分两种原因: 我要说话

现实中这两种情况都会有,前者是开发者自己的问题,比如不管三七二十一给第三方模块版本依赖写了个latest,然后别人发布了个更高大上的不兼容新版本,开发者的代码却跪了。 我要说话

后面一种情况,就是模块开发者的问题了,有可能是发布了一个兼容版本,但是引入了BUG;或者是模块依赖别的模块时没有遵循semver规范,即 开发者A 兼容依赖 模块B latest依赖 模块C,然后C发布不兼容版本,A和B全跪。套娃BUG,隔山打牛,怕不怕。。。 我要说话

作为一个开发者,我能控制我的代码,我的package.json符合规范,但是我控制不了三方模块的代码,也控制不了三方模块的package.json符合规范。 我要说话

于是有了。。。 npm-shrinkwrap.json。安装好依赖后,npm shrinkwrap可以生成npm-shrinkwrap.json文件,对本次安装的所有三方模块和三方模块依赖的三方模块等,的版本树,进行记录并锁定。下一次安装的时候,会按照shrinkwrap.json里边的记录来安装所有的模块。 我要说话

这算是一种设计对工程的妥协吧,设计很美好,而现实中工程上的bug会很多。然而… 模块升级不一定是带来bug的(虽然这种情况很多),也有可能是修bug的, 所以这一妥协,就妥协出了后来的一系列问题。 我要说话

npm v5.0.0 诞生

设计者意识到上面的问题在工程中是客观普遍存在的,于是npm v5.0.0中,除非手动生成了shrinkwrap.json文件,否则在npm install的时候会自动生成一个同功能的package-lock.json。 我要说话

此时,每次重新下载依赖模块时,都会完全按照package-lock.json中记载的去下载。然而就如上面所说,模块版本升级不一定是带来bug的,也有可能是修复bug的啊,还含有可能带上新feature。 我要说话

我更新了package.json中的模块版本,npm install,结果发现按照的还是老版本? 看看issue里这位老哥,都被逼的把 npm install 改成 rm -f package-lock.json && npm install 我要说话

npm v5.1.0 迷惑行为

为了解决上面的问题,npm v5.1.0中,npm install的时候,changelog中写着,如果手动更新了package.json,那么install的时候会把package.json中的版本更新到package-lock.json中去。解决了上面的问题,对吧? 我要说话

理想中的:package.json中依赖[email protected],package-lock.json中是[email protected],npm install之后两个文件中都变成[email protected]我要说话

这个特性确实是ok了,奈何大家发现,从git上拉代码下来,安装所有的依赖模块时,package.json和package-lock.json中都写着[email protected],然后此时作者发布了一个 [email protected]兼容版本,此时npm install之后,安装的却是兼容版本[email protected]。好了,又回到了最开始的场景,假如[email protected]发布了一个BUG 。。。 我要说话

这个版本里package-lock.json相当于是失效了,我反正是没理解,感觉这有点像是npm发布了一个带bug的版本。 我要说话

npm v5.4.2 拨乱反正

对于5.1.0版本起的问题,npm维护者在这个issue里给出了回答(然而我在changelog里边没有看到相关描述),从5.4.2版本开始,逻辑变更为: 我要说话

  • 如果只有一个 package.json 文件,运行 npm install,会生成新的 package-lock.json 文件
  • 如果 package.json 的 semver-range version 和 package-lock.json 中版本兼容,即使此时 package.json 中有新的版本,执行 npm install 也还是会根据 package-lock.json 下载
  • 如果手动修改了 package.json 中的依赖版本,且和 package-lock.json 中版本不兼容,那么执行 npm install 时 package-lock.json 将会更新到兼容 package.json 的版本

这下终于科学了 我要说话

nodejs版本 npm版本 锁定方案 锁定描述

<8.0.0 <5.0.0 shrinkwrap.json 手动npm shrinkwrap生成,根据shrinkwrap.json锁定所有版本

<=8.1.4 <5.1.0 package-lock.json 自动生成,锁定所有版本

<=8.6.0 <5.4.2 package-lock.json 自动生成,不锁定任何版本

>8.6.0 >=5.4.2 package-lock.json 自动生成,锁定兼容版本,不锁定非兼容版本

要不要使用package-lock.json

说了那么多,到底要不要使用lock文件呢?这里有讨论 我要说话

我的理解:
好处:能尽量保证项目的稳定,不受海量三方模块发布的影响
坏处:底层基础库的修复bug兼容更新无法自动应用,需要删除lock重新生成或者手动修改lock 我要说话

如果使用了大量第三方模块,觉得三方模块及三方模块的依赖不可控,那么用lock锁定它们的兼容版本依赖,防止三方模块发布的兼容版本整崩整个项目;
如果觉得依赖的大部分模块可控(比如是公司内部团队维护),且这些模块作为基础模块会偶尔发布底层性能优化/bug修复等,那么可以考虑不使用lock文件。我要说话

本文链接:https://www.zoucz.com/blog/2020/05/31/f23b2980-a30c-11ea-90b5-eb40e9720ed0/我要说话

☞ 参与评论我要说话


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK