一次 yarn 安裝依賴失敗,讓我重新認(rèn)識了 NPM 版本號規(guī)則
現(xiàn)代的前端開發(fā)、Node.js 后端開發(fā)中 NPM 包管理是最基礎(chǔ)也是最關(guān)鍵的一部分,本文將從一個問題開始,闡述 NPM 版本控制的工作原理,我相信這是每一個使用了 NPM 的開發(fā)人員都應(yīng)該熟悉的知識。
一個依賴安裝失敗示例
事情的經(jīng)過是前一天測試還一切正常,第二天部署時卻提示 yarn 安裝依賴失敗,下面是本地復(fù)現(xiàn)的結(jié)果,如下圖所示:
yarn 安裝失敗
一個明顯的提示是 bson@5.0.0? 這個依賴不再支持 Node.js 14.20.1? 以下版本,但是項目的 dependencies? 中也沒有指定這個包啊,了解 MongoDB 的同學(xué)應(yīng)該知道 bson? 是 Mongo? 實現(xiàn)的一個類 JSON 的二進(jìn)制存儲格式。
為了一探究竟,執(zhí)行 yarn --ignore-engines? 先忽略這個引擎檢測,看下 yarn.lock 文件中 bson 的依賴關(guān)系。
mongoose@^5.3.0? 是項目中的依賴,實際安裝后使用的版本為 5.13.5?,之后又依賴了 @types/mongodb?,問題來了,這里竟然使用了 @types/bson: *? 要知道在 NPM 的版本號規(guī)則里 *? 號是不會鎖定版本的,每次都會升級為最新版本,也就是最后的 bson: 5.0.0。
查了下 bson? 這個庫的 CHANGELOG 發(fā)現(xiàn)其在 2023-01-31? 號發(fā)布了 5.0.0,要求 Node.js 版本必須大于 14.20.1,上面報錯顯然當(dāng)前版本不滿足。
庫的版本升級很正常,了解 NPM 版本號規(guī)則的同學(xué)應(yīng)該知道 “bson: 5.0.0 ” 這是一個大版本,會存在不向前兼容的情況,這里的問題在于 ?@types/mongodb? 直接使用了 ?@types/bson: *?,每次安裝都會升級到最新,是有點不講 “碼德”,這里是個坑,NPM 上查了 @types/mongodb 這個包,發(fā)現(xiàn)已經(jīng)被廢棄了,如下圖所示:
mongoose? 這個包的影響版本為:?mongoose 5.11 ~ 5.13.15。
這里先拋出一個問題:“為什么安裝時使用的 mongoose@^5.3.0? 安裝成功后卻變成了 5.13.15”?
NPM 的語義版本控制
在發(fā)布 NPM 模塊新版本時,建議遵循 “語義版本控制” 考慮使用這樣的版本號x.y.z 控制,如下所示:
版本號規(guī)則:
- 主版本:做了不兼容的 API 修改,不會向前兼容,一般也稱為大版本,當(dāng)項目依賴需要升級到大版本時需要注意。
- 次版本:通常是做了向前兼容的新功能增加,一般也稱為小版本。
- 補(bǔ)丁版本:修復(fù)現(xiàn)有的一些錯誤,也是向前兼容的。
在發(fā)布 NPM 包時建議從 1.0.0 開始,例如:
- 1.0.0:新產(chǎn)品首次發(fā)布。
- 1.0.1:向前兼容的補(bǔ)丁版本,修改第 3 位數(shù)。
- 1.1.0:向前兼容增加新特性,增加中間數(shù)字,將最后一位置為 0。
- 2.0.0:不向前兼容的更新,增加第一位數(shù)字,將第二、三位數(shù)置為 0。
語義化版本號的幾種表示方法:
- ^1.1.2:^ 是 NPM 安裝后的默認(rèn)符號,保持高版本不升級,次版本、補(bǔ)丁版本升級到最新,例如:^1.1.2 等價于 1.1.2 >= ^1.1.2 < 2.0.0。
- ~1.1.3?:波浪符 ~ 只會升級補(bǔ)丁版本,例如:~1.1.3 等價于 1.1.3 >= ~1.1.3 <1.2.0。
- 1.1.3:不加任何符號表示鎖定了這個版本,不會進(jìn)行任何升級。
- * 或 "":* 號或者空字符 "",不會鎖定版本,每次都會升級到最新版本,前面提的問題就是這個導(dǎo)致的。
- 1.0.0-alpha.1:使用 alpha、rc 等標(biāo)識的表示該版本是一個預(yù)發(fā)布版本,該版本可能無法滿足預(yù)期的兼容性需求,正式環(huán)境不要用。
- 一個非語義話版本號的示例 v1.0.0:在一些版本控制的系統(tǒng)中通常用 v 表示版本號,例如 git tag v1.0.0,但它并不是語義化版本號。
了解了語義化版本號規(guī)則后,應(yīng)該要知道上面提出的一個問題:“為什么安裝時使用的 mongoose@^5.3.0? 安裝成功后卻變成了 5.13.15?”,因為版本號前加 ^ 符號,它表示的是第一位保持不變、最后兩位升級到最新。
依賴鎖定 - 解決版本不一致問題
考慮一個問題,項目第一次添加一個模塊的依賴是 ^1.2.3?,過了兩周另一個同事需要修這個項目,此時依賴已經(jīng)更新到 1.3.0 他在重新安裝后就會得到最新的版本,這會帶來一個問題,每個人得到依賴版本不一致,該如何確保團(tuán)隊成員的依賴版本都是一致呢?
解決依賴版本不一致的問題一種方法是 “固定依賴版本”,但在實際做法中這種很少見,大多數(shù)時候沒有意識到一個問題 “安全修復(fù)”,通過版本號前加 ^ 或 ~ 符號我們可以得到補(bǔ)丁版本錯誤修復(fù)、向前兼容的小版本新功能。
解決依賴版本不一致的另一種方法是通過 lock 文件(NPM 中的 package-lock.json? 或 yarn 中的 yarn.lock )來解決同一個項目團(tuán)隊成員之間依賴版本不一致的問題,在使用 npm 或 yarn 安裝之前會先檢查 lock 文件上的版本,并來安裝它們,有必要將 lock 文件推送至 git 倉庫。
如果需要將依賴項更新到指定范圍的最新版本,只需要執(zhí)行 npm update 命令,該命令會遵循語義化版本控制對依賴進(jìn)行升級,同時也會更新 lock 文件。