依赖包版本号

npm采用了semver规范作为依赖版本管理方案。

按照semver的约定,一个npm依赖包的版本格式一般为:主版本号.次版本号.修订号x.y.z),每个号的含义是:

  • 主版本号(也叫大版本,major version

    大版本的改动很可能是一次颠覆性的改动,也就意味着可能存在与低版本不兼容的API或者用法,(比如 vue 2 -> 3)。

  • 次版本号(也叫小版本,minor version

    小版本的改动应当兼容同一个大版本内的API和用法,因此应该让开发者无感。所以我们通常只说大版本号,很少会精确到小版本号。

    如果大版本号是 0 的话,表示软件处于开发初始阶段,一切都可能随时被改变,可能每个小版本之间也会存在不兼容性。所以在选择依赖时,尽量避开大版本号是 0 的包。

  • 修订号(也叫补丁,patch

    一般用于修复bug或者很细微的变更,也需要保持向前兼容。

常见的几个版本格式如下:

  • “1.2.3”

    表示精确版本号。任何其他版本号都不匹配。在一些比较重要的线上项目中,建议使用这种方式锁定版本。

  • “^1.2.3”

    表示兼容补丁和小版本更新的版本号。官方的定义是“能够兼容除了最左侧的非 0 版本号之外的其他变化”(Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple)。这句话很拗口,举几个例子大家就明白了:

"^1.2.3" 等价于 ">= 1.2.3 < 2.0.0"。即只要最左侧的 "1" 不变,其他都可以改变。所以 "1.2.4", "1.3.0" 都可以兼容。

"^0.2.3" 等价于 ">= 0.2.3 < 0.3.0"。因为最左侧的是 "0",那么只要第二位 "2" 不变,其他的都兼容,比如 "0.2.4""0.2.99""^0.0.3" 等价于 ">= 0.0.3 < 0.0.4"。大版本号和小版本号都为 "0" ,所以也就等价于精确的 "0.0.3"
  • 从这几个例子可以看出,^ 是一个兼具更新和安全的写法,但是对于大版本号为 1 和 0 的版本还是会有不同的处理机制的。

  • “~1.2.3”

    表示只兼容补丁更新的版本号。关于 ~ 的定义分为两部分:如果列出了小版本号(第二位),则只兼容补丁(第三位)的修改;如果没有列出小版本号,则兼容第二和第三位的修改。我们分两种情况理解一下这个定义:

"~1.2.3" 列出了小版本号 "2",因此只兼容第三位的修改,等价于 ">= 1.2.3 < 1.3.0"。

"~1.2" 也列出了小版本号 "2",因此和上面一样兼容第三位的修改,等价于 ">= 1.2.0 < 1.3.0"。

"~1" 没有列出小版本号,可以兼容第二第三位的修改,因此等价于 ">= 1.0.0 < 2.0.0"

  • 从这几个例子可以看出,~ 是一个比^更加谨慎安全的写法,而且~并不对大版本号 0 或者 1 区别对待,所以 “~0.2.3” 与 “~1.2.3” 是相同的算法。当首位是 0 并且列出了第二位的时候,两者是等价的,例如 “~0.2.3” 和 “^0.2.3”。

  • “1.x” 、“1.X”、1.“、“1”、”"

    表示使用通配符的版本号。x、X、* 和 (空) 的含义相同,都表示可以匹配任何内容。具体来说:

"*" 、"x" 或者 (空) 表示可以匹配任何版本。

"1.x", "1.*" 和 "1" 表示匹配主版本号为 "1" 的所有版本,因此等价于 ">= 1.0.0 < 2.0.0"。

"1.2.x", "1.2.*" 和 "1.2" 表示匹配版本号以 "1.2" 开头的所有版本,因此等价于 ">= 1.2.0 < 1.3.0"。

  • “1.2.3-alpha.1”、“1.2.3-beta.1”、“1.2.3-rc.1”

带预发布关键词的版本号。先说说几个预发布关键词的定义:

alpha(α):预览版,或者叫内部测试版;一般不向外部发布,会有很多bug;一般只有测试人员使用。

beta(β):测试版,或者叫公开测试版;这个阶段的版本会一直加入新的功能;在alpha版之后推出。

rc(release candidate):最终测试版本;可能成为最终产品的候选版本,如果未出现问题则可发布成为正式版本。

以包开发者的角度来考虑这个问题:假设当前线上版本是 “1.2.3”,如果我作了一些改动需要发布版本 “1.2.4”,但我不想直接上线(因为使用 “~1.2.3” 或者 “^1.2.3” 的用户都会直接静默更新),这就需要使用预发布功能。因此我可能会发布 “1.2.4-alpha.1” 或者 “1.2.4-beta.1” 等等。

">1.2.4-alpha.1"表示接受 "1.2.4-alpha" 版本下所有大于 1 的预发布版本。因此 "1.2.4-alpha.7" 是符合要求的,但 "1.2.4-beta.1" 和 "1.2.5-alpha.2" 都不符合。此外如果是正式版本(不带预发布关键词),只要版本号符合要求即可,不检查预发布版本号,例如 "1.2.5", "1.3.0" 都是认可的。

"~1.2.4-alpha.1" 表示 ">=1.2.4-alpha.1 < 1.3.0"。这样 "1.2.5", "1.2.4-alpha.2" 都符合条件,而 "1.2.5-alpha.1", "1.3.0" 不符合。

"^1.2.4-alpha.1" 表示 ">=1.2.4-alpha.1 < 2.0.0"。这样 "1.2.5", "1.2.4-alpha.2", "1.3.0" 都符合条件,而 "1.2.5-alpha.1", "2.0.0" 不符合。

版本号还有更多的写法,例如范围(a - b),大于等于号(>=),小于等于号(<=),或(||)等等,因为用的不多,这里不再展开。详细的文档可以参见语义化版本(semver)。它同时也是一个 npm 包,可以用来比较两个版本号的大小,以及是否符合要求等。

依赖包版本管理

npm 2.x/3.x已成为过去式,在npm 5.x以上环境下(版本最好在5.6以上,因为在5.0 ~ 5.6中间对package-lock.json的处理逻辑更新过几个版本,5.6以上才开始稳定),管理项目中的依赖包版本你应该知道(以^版本为例,其他类型版本参照即可):

  1. 在大版本相同的前提下,如果一个模块在package.json中的小版本要大于package-lock.json中的小版本,则在执行npm install时,会将该模块更新到大版本下的最新的版本,并将版本号更新至package-lock.json。如果小于,则被package-lock.json中的版本锁定。
// package-lock.json 中原版本
"clipboard": {
  "version": "1.5.10", 
},
"vue": {
  "version": "2.6.10",
}
// package.json 中修改版本
"dependencies": {
  "clipboard": "^1.5.12",
  "vue": "^2.5.6"
  ...
}

// 执行完 npm install 后,package-lock.json 中
"clipboard": {
  "version": "1.7.1", // 更新到大版本下的最新版本
},
"vue": {
  "version": "2.6.10", // 版本没发生改变
}

  1. 如果一个模块在package.jsonpackage-lock.json中的大版本不相同,则在执行npm install时,都将根据package.json中大版本下的最新版本进行更新,并将版本号更新至package-lock.json
// package-lock.json 中原版本
"clipboard": {
  "version": "2.0.4",
}
// package.json 中修改版本
"dependencies": {
  "clipboard": "^1.6.1",
}

// 执行完npm install后,package-lock.json 中
// 
"clipboard": {
  "version": "1.7.1", // 更新到大版本下的最新版本
}

  1. 如果一个模块在package.json中有记录,而在package-lock.json中无记录,执行npm install后,则会在package-lock.json生成该模块的详细记录。同理,一个模块在package.json中无记录,而在package-lock.json中有记录,执行npm install后,则会在package-lock.json删除该模块的详细记录。

  2. 如果要更新某个模块大版本下的最新版本(升级小版本号),请执行如下命令:

npm update packageName
  1. 如果要更新到指定版本号(升级大版本号),请执行如下命令:
npm install packageName@x.x.x

  1. 卸载某个模块,请执行如下命令:
npm uninstall packageName

  1. 安装模块的确切版本:
npm install packageName -D/S --save-exact  # 安装的版本号将会是精准的,版本号前面不会出现^~字符

通过上述的命令来管理依赖包,package.jsonpackage-lock.json中的版本号都将会随之更新。

我们在升级/卸载依赖包的时候,尽量通过命令来实现,避免手动修改package.json中的版本号,尤其不要手动修改package-lock.json

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 3 个月前
8c391e04 6 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐