npm包的依赖版本比较

3,438 阅读3分钟

项目中遇到的问题

有个npm包叫a,项目的dependencies有a和b两个依赖,a的版本是version1。b中也依赖了a这个包,版本是version2。在项目打包的时候,会把a的这两个版本都打进build文件中。本文主要分析对同一个包有多个版本依赖的情况。

npm如何管理node_modules

在npm 3.0版本之前,node_modules里面的依赖是一种树形的嵌套结构,这样会造成很多依赖重复安装,并且node_modules的层级会非常深。

在npm 3.0的版本中,会先分析所有的依赖关系,尽可能的把依赖层级拍平。如果一个包没有被重复依赖,它会安装在node_modules的第一层。当同一个包出现版本冲突时,会根据就近原则,把对应的依赖安装在当前包的node_modules文件夹中。

版本号管理:SemVer

SemVer的中文名称是语义化版本控制规范。npm默认使用SemVer来进行模块的版本控制。一个发布到npm的包要严格遵守SemVer的版本规范,不然会发布失败。

版本格式

主版本号.次版本号.修订号,可以用x.y.z的写法来简单表示。

  • 主版本号:只有在新增了无法向下兼容的API的时候,才可以递增。
  • 次版本号:只有在新增了可以向下兼容的新功能的时候,才可以递增,可以理解为feature版本。
  • 修订号:只有在做了向下兼容的修正时才可以递增,可以理解为bug fix版本

先行版本

当要进行大版本迭代的时候,或者增加一些核心的功能,但又不能保证新版本百分之百正常,这个时候就可以发布先行版本。SemVer规范中使用alpha、beta和rc来修饰先行版本。

  • alpha:内部版本
  • beta:公测版本
  • rc:Release candiate,正式版本的候选版本

先行版本的版本号可以使用:1.0.0-alpha、1.0.0-beta.1、1.0.0- rc.1、1.0.0-0.3.7等。

版本号的优先级

进行版本号比较时,x、y、z依次比较

先行版本号的规则是rc > beta > alpha

1.0.0 < 2.0.0 < 2.1.0 < 2.1.1  ​  

1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0- rc.1 < 1.0.0  

常用的版本升级符号

^符: ^1.2.3 ^0.2.5 ^0.0.4

^符是npm安装依赖的默认方式。

按照版本的语义,就是完全信任包拥有者能够根据语义进行正确的包升级,不会引入具有破坏性的改变,并且做到对老版本的兼容。

^1.2.3  <=>  >=1.2.3 <2.0.0
^0.2.3  <=>  >=0.2.3 <0.3.0
^0.0.3  <=>  >=0.0.3 <0.0.4

^1.2.x  <=>  >=1.2.0 <2.0.0
^0.0.x  <=>  >=0.0.0 <0.1.0
^0.0    <=>  >=0.0.0 <0.1.0

^1.2.3-beta.2  <=>  >=1.2.3-beta.2 <2.0.0
^0.0.3-beta    <=>  >=0.0.3-beta <0.0.
~符: ~1.2.3 ~1.2 ~1

~符是老版本npm的默认方式,它只会安装升级z位的版本,是一种很保守的依赖管理策略。

~1.2.3  <=>  >=1.2.3 <1.(2+1).0 := >=1.2.3 <1.3.0
~1.2    <=>  >=1.2.0 <1.(2+1).0 := >=1.2.0 <1.3.0 (Same as 1.2.x)
~1      <=>  >=1.0.0 <(1+1).0.0 := >=1.0.0 <2.0.0 (Same as 1.x)
~0.2.3  <=>  >=0.2.3 <0.(2+1).0 := >=0.2.3 <0.3.0
~0.2    <=>  >=0.2.0 <0.(2+1).0 := >=0.2.0 <0.3.0 (Same as 0.2.x)
~0      <=>  >=0.0.0 <(0+1).0.0 := >=0.0.0 <1.0.0 (Same as 0.x)

~1.2.3-beta.2  <=>  >=1.2.3-beta.2 <1.3.0
固定版本:2.3.1

固定版本的依赖是确定的,除非手动升级,不然每次都安装相同的版本。

版本冲突

当一个依赖包出现版本冲突时,会根据这个包不同的升级策略来确定版本号。如果最后的版本号相同,只会在项目的node_modules里面安装这个版本的依赖;如果版本号不同,则两个版本号的依赖都会安装。

因为每个npm包的版本更迭都不同,所以并没有一个固定的规则去适用所有的情况。当一个包被多次依赖的时候,需要去npm的官网去查看这个包所有的版本,然后根据依赖的升级规则,去判断这个包是否会版本冲突。

以redux作为一个例子。

下面是当前时间,redux latest这个tag下面的版本号

4.0.1
4.0.0
3.7.2
3.7.1
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
3.4.0
3.3.1
3.3.0
3.2.0
...
~3.7.0   <=>   ^3.6.0
3.7.2    <=>   ^3.6.0
^3.3.0   <=>   ^3.5.0
^3.6.0   <!=>  ^4.0.0