semver:語義化版本規範在 Node.js 中的實現

精子又開了一個新系列!我計劃在這個系列中每篇文章介紹一個 NPM(Node Package Manager)上的包,來向大家分享一些我在使用這個包的過程中的經驗,同時也會延伸到一些相關的技術,例如如果介紹 redis 這個包,那麼我也會順便介紹一下 Redis. 因為對於一些使用廣泛的包我可能需要更多的時間來搜集資料,所以一開始會從一些比較小而專的包開始。

semver

n我們先從 semver 這個不起眼的包開始,它是 語義化版本(Semantic Versioning)規範 的一個實現,目前是由 npm 的團隊維護的,實現了版本和版本範圍的解析、計算、比較,在 NPM 的被依賴(Most depended-upon)榜單中排名 34.

nSemantic Versioning 是由 GitHub 的聯合創始人 Tom Preston-Werner 建立的一個有關如何命名軟體和庫(包)版本的規範,用以解決在大型項目中對依賴的版本失去控制的問題(例如你可能因為害怕不兼容而不敢去更新依賴)。現在 Semantic Versioning 已經在開源社區中得到了廣泛的認同,Node.js 的包管理工具 npm 也完全基於 Semantic Versioning 來管理依賴的版本。

semver 定義了兩種概念:

  • 版本是指例如 0.4.1、1.2.7、1.2.4-beta.0 這樣表示包的特定版本的字元串。
  • 範圍則是對滿足特定規則的版本的一種表示,例如 1.2.3-2.3.4、1.x、^0.2、>1.4.

在這兩種概念上可以進行很多種計算,例如比較兩個版本的大小、判斷一個版本是否滿足一個範圍、判斷一個版本是否比範圍中的任何版本都大等。

顯然這個包的使用場景就是與版本號打交道。例如你有一個客戶端工具,需要在每次啟動時向伺服器發起一個查詢來檢查更新,那麼用 semver 去比較版本將會是一個很好的選擇:

console.log(semver.gt(lastestVersion, currentVersion) ? New Update available : Already lastest version);n

基於 Semantic Versioning 規範,我們還可以計算出兩個版本之間的差異程度:

console.log(semver.diff(lastestVersion, currentVersion) == major ? Major Release : Minor or patch Release );n

n再比如你在實現一個插件化的系統,每個插件(在 package.json 中)都會聲明一個所兼容的主程序的版本範圍,而主程序在載入插件時需要檢查這個版本並使當地給出警告:

plugins.forEach(function(plugin) {n if (!semver.satisfies(platformVersion, plugin.engines.platform))n console.log(plugin.name, require, plugin.engines.platform, but unable to meet);n});n

n在你使用 express 設計一個支持多種版本的 API 伺服器時,你可以這樣做:

app.get(/, apiVersion(<0.6), function(req, res) {n res.send(Less than 0.6);n});nnapp.get(/, apiVersion(1.2.3 - 2.3.4), function(req, res) {n // ...n});nnapp.get(/, apiVersion(*), function(req, res) {n res.send(Unsupported version);n});n

n其中 apiVersion 中間件的一個簡單實現:

function apiVersion(range) {n return function(req, res, next) {n if (semver.satisfies(req.headers[x-api-version], range))n next();n elsen next(route); // skip current routen };n}n

也許你用字元串計算再配合一點正則也可以完成上述的場景,但你很難做到對 Semantic Versioning 的完備支持,在之後發布新版本後撰寫版本號的時候也會受到限制,例如 semver 可以正確地比較 0.9.0 和 0.10.0 以及 0.9.0-beta.1,但自行實現這些支持將會非常繁瑣。

所以其實選擇 semver 的理由很簡單 —— 讓專業的包去完成專業的工作,相信這也是在 Node.js 社區得到了廣泛認同的觀點。

推薦閱讀:

TAG:Nodejs | npm | 版本号 |