Node.js 依賴管理(二)—版本號管理1.x.x
原文鏈接:https://www.novenblog.xin/detail/?id=67
本文拜讀百度@小蘑菇哥哥的Node.js 中的依賴管理,正文從這裏開始~
在引入某個依賴項時,采用如下代碼:
npm i xxx -D 或 npm i xxx -S
如果沒有明確的指定xxx的引用版本,則會默認安裝最新版本的包,等同於:
npm i xxx@latest -D
最後生成的package.json中的依賴項版本如下:
以a.b.c舉例,詳解版本號
a.b.c版本號的含義如下:a - 主要版本(也叫大版本,major version)
大版本的升級很可能意味著與低版本不兼容的 API 或者用法,是一次顛覆性的升級(想想 webpack 3 -> 4)。
b - 次要版本(也叫小版本,minor version)
小版本的升級應當兼容同一個大版本內的 API 和用法,因此應該對開發者透明。所以我們通常只說大版本號,很少會精確到小版本號。
特殊情況是如果大版本號是 0 的話,意味著整個包處於內測狀態,所以每個小版本之間也可能會不兼容。所以在選擇依賴時,盡量避開大版本號是 0 的包。
c - 補丁 (patch)
一般用於修復 bug 或者很細微的變更,也需要保持向前兼容。
之後我們看一下常規的版本號寫法:
“1.2.3” - 無視更新的精確版本號表示只依賴這個版本,任何其他版本號都不匹配。在一些比較重要的線上項目中,我比較建議使用這種方式鎖定版本。前陣子的 npm 挖礦以及 ant-design 彩蛋,其實都可以通過鎖定版本來規避問題(彩蛋略難一些,挖礦是肯定可以規避)。
“^1.2.3” - 兼具更新和安全的折中考慮
這是 npm i xxx —save 之後系統生成的默認版本號(^ 加上當前最新版本號),官方的定義是“能夠兼容除了最左側的非 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”。那麽只要這個 “2” 不變,其他的都兼容,比如 “0.2.4” 和 “0.2.99”。
-
“^0.0.3” 等價於 “>= 0.0.3 < 0.0.4”。這裏最左側的非 0 只有 “3”,且沒有其他版本號了,所以這個也等價於精確的 “0.0.3”。
從這幾個例子可以看出,^ 是一個更新和安全兼容的寫法。一般大版本號升級到 1 就表示項目正式發布了,而 0 開頭就表示還在測試版,這也是 ^ 區別對待兩者的原因。
“~1.2.3” - 比 ^ 更加安全的小版本更新
關於 ~ 的定義分為兩部分:如果列出了小版本號(第二位),則只兼容 patch(第三位)的修改;如果沒有列出小版本號,則兼容第二和第三位的修改。我們分兩種情況理解一下這個定義:
“~1.2.3” 列出了小版本號(2),因此只兼容第三位的修改,等價於 “>= 1.2.3 < 1.3.0”。
“~1.2” 也列出了小版本號,因此和上面一樣兼容第三位的修改,等價於 “>= 1.2.0 < 1.3.0”。
“~1” 沒有列出小版本號,可以兼容第二第三位的修改,因此等價於 “>= 1.0.0 < 2.0.0”
和 ^ 不同的是,~ 並不對 0 或者 1 區別對待,所以 “~0” 等價於 “>= 0.0.0 < 1.0.0”,和 “~1” 是相同的算法。比較而言,~ 更加謹慎。當首位是 0 並且列出了第二位的時候,兩者是等價的,例如 ~0.2.3 和 ^0.2.3。
在 nodejs 的上古版本(v0.10.26,2014年2月發布的),npm i —save 默認使用的是 ~,現在已經改成 ^ 了。這個改動也是為了讓使用者能最大限度的更新依賴包。
“1.x” 或者 “1.“ - 使用通配符
這個比起上面那兩個符號就好理解的多。x(大小寫皆可)和 的含義相同,都表示可以匹配任何內容。具體來說:
“*” 或者 “” (空字符串) 表示可以匹配任何版本。
“1.x”, “1.*” 和 “1” 都表示要求大版本是 1,因此等價於 “>=1.0.0 < 2.0.0”。
“1.2.x”, “1.2.*” 和 “1.2” 都表示鎖定前兩位,因此等價於 “>= 1.2.0 < 1.3.0”。
因為位於結尾的通配符一般可以省略,而常規也不太可能像正則那樣把匹配符寫在中間,所以大多數情況通配符都可以省略。使用最多的還是匹配所有版本的 * 這個了。
“1.2.3-beta.2” - 帶預發布關鍵詞的,如 alpha, beta, rc, pr 等
先說預發布的定義,我們需要以包開發者的角度來考慮這個問題。假設當前線上版本是 “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” 版本所有大於1的 alpha 預發布版本。因此如 “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),大於小於號(>=a <b),或(表達式1 || 表達式2)等等,因為用的不多,這裏不再展開。詳細的文檔可以參見 semver,它同時也是一個 npm 包,可以用來比較兩個版本號的大小,以及是否符合要求等。
下面是其他相關文章推薦:
-
Node.js 依賴管理(一)—區分dependencies和devDependencies
-
Node.js 依賴管理(三)—package-lock.json詳解
Node.js 依賴管理(二)—版本號管理1.x.x