聊聊 npm 的語義化版本(Semver)

前言

現在我們要開發一個項目,我們都知道爲了方便項目管理,要寫一個版本號,那開發的時候初始的版本號是多少呢?是 1.0.0 還是 0.0.1 開始?

如果一個版本號爲 X.Y.Z,什麼時候是 X 應該加  1,什麼時候 Y 應該加 1 ,什麼時候 Z 應該加 1,加 1 遵循十進制嗎?比如 1.0.9 的下一個版本應該是 1.1.0 嗎?

我們經常看到一些項目的版本還帶着後綴,比如 React 的 18.0.0-rc.3、  Vue 的 2.7.0-alpha.12,這些又是什麼意思呢?這些後綴是固定字段還是可以自定義的呢?

SemVer 規範

實際上,語義化的版本控制並不是一個創新性的想法,即便我們不知道這些,我們也在做類似的事情,但一個明確的規範將會讓版本邏輯更清晰的傳達給其他開發者。

所以由 Gravatars 創辦者兼 GitHub 共同創辦者 Tom Preston-Werner 就建立了語義化版本控制的規範, semantic version 簡稱 semver,於是這個規範就叫做 SemVer 規範,規範地址爲:https://semver.org/lang/zh-CN/[1]

我簡單講講其中的內容,大家也很容易理解:

版本號的格式

標準的版本號必須採用 X.Y.Z 的格式,其中 X、Y 和 Z 爲非負的整數,且禁止在數字前方補零。X 是主版本號、Y 是次版本號、而 Z 爲修訂號,英文對應表示爲 major、minor、patch,每個元素必須以數值來遞增。例如:1.9.1 -> 1.10.0 -> 1.11.0。

主版本號爲零(0.y.z)的軟件處於開發初始階段,一切都可能隨時被改變。

1.0.0 的版本號用於界定公共 API 的形成。

版本號的遞增邏輯

修訂號 Z(x.y.Z | x > 0)必須在只做了向下兼容的修正時才遞增。這裏的修正指的是針對不正確結果而進行的內部修改。

次版本號 Y(x.Y.z | x > 0)必須在有向下兼容的新功能出現時遞增。在任何公共 API 的功能被標記爲棄用時也必須遞增。也可以在內部程序有大量新功能或改進被加入時遞增,其中可以包括修訂級別的改變。每當次版本號遞增時,修訂號必須歸零。

主版本號 X(X.y.z | X > 0)必須在有任何不兼容的修改被加入公共 API 時遞增。其中可以包括次版本號及修訂級別的改變。每當主版本號遞增時,次版本號和修訂號必須歸零。

簡單的總結下就是:

  1. 當有不兼容的 API 更改時,則升級主版本號

  2. 當以向後兼容的方式添加功能時,則升級次版本號

  3. 當進行向後兼容的缺陷修復時,則升級修訂號

關於先行版本

先行版本號可以被標註在修訂版之後,先加上一個連接號再加上一連串以句點分隔的標識符來修飾。標識符必須由 ASCII 字母數字和連接號組成,且禁止留白。數字型的標識符禁止在前方補零,舉個例子:1.0.0-alpha.6

先行版的優先級低於相關聯的標準版本,舉個例子 1.0.0-alpha < 1.0.0

被標上先行版本號則表示這個版本並非穩定而且可能無法滿足預期的兼容性需求。

問題回答

其實規範內容並不多,回到開頭時的第一個問題:

Q:在 0.y.z 初始開發階段,我該如何進行版本控制?A:最簡單的做法是以 0.1.0 作爲你的初始化開發版本,並在後續的每次發行時遞增次版本號。

Q:如何判斷髮布 1.0.0 版本的時機?A:當你的軟件被用於正式環境,它應該已經達到了 1.0.0 版。如果你已經有個穩定的 API 被使用者依賴,也會是 1.0.0 版。如果你很擔心向下兼容的問題,也應該算是 1.0.0 版了。

alpha beta 和 rc

現在我們知道,先行版本中 - 後的字符是自定義的,我們經常看到一些庫的版本會帶 alpha、beta 之類的字樣,就以 Vue 爲例,有 3.0.0-alpha.133.0.0-beta.13.0.0-rc.1,這些表示什麼意思呢?

一般來說:

alpha 表示內部測試版,主要給開發和測試找 bug 用,不建議用戶下載 beta 表示公開測試版,你可以提前嘗試一些功能 rc 是 Release Candidate(候選版本)的縮寫,表示該版本功能不再增加,和最終發佈版功能一樣,有點像預覽版,然後可能再改改一些小 bug,就會到正式的版本了。

當然庫也可以使用自己的版本邏輯,就比如 React,它還有 next 版和 experimental 版,具體的發佈邏輯 React 官網也有寫:https://react.docschina.org/docs/release-channels.html[2]

npm 指定版本範圍

我們經常在 package.json 文件中看到版本號前出現 ~ ^ 等字符,比如:

{
   "dependencies"{
    "react""^1.2.3
    "vue": "~1.2.3",
  }
}

這些標識符的作用相信我們多少都知道一點,比如:

^ 表示次版本號的更新,比如 ^1.2.3就表示以後安裝的版本 >=1.2.3 <2.0.0``~ 表示修訂版本號的更新,比如 ~1.2.3就表示以後安裝的版本 >=1.2.3 <1.3.0

當然具體的邏輯會更復雜一點,比如:

^只會執行不更改最左邊非零數字的更新,所以:

  1. ^0.2.3 相當於 >=1.2.3 <2.0.0

  2. ^0.0.3相當於>=0.0.3 <0.0.4

  3. ^1.2.3-beta.2 相當於 >=1.2.3-beta.2 <2.0.0,這其中 1.2.3-beta.4是可以的,但 1.2.4-beta.2就不行了

~如果指定了次版本號,則會只進行修訂版本號的更新,如果沒有指定,則會進行此版本號的更新,所以:

  1. ~1.2.3 相當於 >=1.2.3 <1.3.0

  2. ~1.2相當於 >=1.2.0 <1.3.0 (相當於 1.2.x)

  3. ~1 相當於 >=1.0.0 <2.0.0 (相當於 1.x)

  4. ~1.2.3-beta.2 相當於 >=1.2.3-beta.2 <1.3.0,這其中 1.2.3-beta.4是可以的,但 1.2.4-beta.2就不行了

除了 ^~,NPM 提供了更多的表示範圍版本的方式:https://docs.npmjs.com/cli/v8/configuring-npm/package-json#dependencies[3]

簡單舉幾個示例:

{
  "dependencies"{
    "foo""1.0.0 - 2.9999.9999",
    "bar"">=1.0.2 <2.1.2",
    "baz"">1.0.2 <=2.3.4",
    "qux""<1.0.0 || >=2.3.1 <2.4.5 || >=2.5.2 <3.0.0",
    "lat""latest",
  }
}

這其中 latest 表示標籤,在默認情況下,npm 使用 latest 標籤來標識軟件包的當前版本。

對應我們安裝包的時候也可以參照這些指定版本安裝:

npm install foo@1.2.3
npm install foo@">=0.1.0 <0.2.0"
npm install foo@latest

npm version

NPM 也提供了 npm version 命令可以更新版本號,具體的語法如下:

npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]

其中最主要的就是 majorminorpatch,比如你當下的項目的 package.jsonversion1.0.0

當你執行 npm version major 後,version 會變成 2.0.0當你執行 npm version minor後,version 會變成 1.1.0當你執行 npm version patch 後,version 會變成 1.0.1

premajorpreminorprepatch 也是同理:

當你執行 npm version premajor後,version 會變成 2.0.0-0當你執行 npm version premajor後,version 會變成 1.1.0-0當你執行 npm version prepatch後,version 會變成  1.0.1-0

而當你執行 npm version prerelease後,version 也會變成 1.0.1-0

prepatchprerelase 的區別在於,prepatch 是增加 patch 號,先行版本號置爲 0,prerelase 則是如果沒有先行版本號,則跟 prepatch 一樣,如果有的話,則會在先行版本號上加 1,舉個例子,當你的版本號爲 1.0.0-0時,

當你執行 npm version prepatch後,version 會變成  1.0.1-0而當你執行 npm version prerelease後,version 會變成 1.0.0-1

你也可以在此基礎上再添加一個 -m 參數:

npm version patch -m "Upgrade to %s for reasons"

其中 %s 表示新的版本號,npm 會創建一個 commit 信息,就相當於 npm 修改了版本號後,又對文件執行了一句 git commit -am "Upgrade to %s for reasons"

更多 npm version 命令可以參考 npm 官方文檔 https://docs.npmjs.com/cli/v8/commands/npm-version[4]

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/ONb3pNkBjI9Jroocr4cztw