你真的知道NPM版本管理規範嗎

NPM Version Management Specification

來源

常規的開發,常規的代碼,不動如山的CI,忽然發生了錯誤,致使失敗,出現如下錯誤:node

1
Build failed: [BABEL] /xxx/xxx/yyy/.xxx.js: You gave us a visitor for the node type OptionalCallExpression but it's not a valid type

 

本地調試之,赫然出現了不同的錯誤:npm

1
Build failed: Cannot find module '@babel/runtime/core-js/object/keys'

 

觀察了一下package.json,含有"babel-runtime": "^6.9.2",因而乎開開心心的安裝了下@babel/runtime => npm install @babel/runtime
BOOOOOM!繼續報錯,尋遍 issue 未發現錯誤緣由以及真正的解決辦法,TnTjson

查看了下框架包,查找了下項目依賴包的依賴包,發現使用了@babel/runtime@7.0.0-beta.41的版本,莫不是版本問題?!換之,修改了下package.json文件以下:babel

1
2
- "babel-runtime": "^6.9.2"
+ "@babel/runtime": "^7.0.0-beta.41"

 

常規rm -rf node_modules && cnpm install,小段時間的等待以後,發現錯誤並無消失,奇了怪了~~框架

繼續查看依賴包的依賴包,發現它要7.0.0-beta.41,而在個人node_modules/黑洞裏的@babel/runtime卻安裝的是7.0.0版本,Bingo,問題找到了,鎖個版本,修改以下:ui

1
2
- "@babel/runtime": "^7.0.0-beta.41"
+ "@babel/runtime": "7.0.0-beta.41"

常規rm -rf node_modules && cnpm install以後,問題消失了,部署跑CI瞧一下,問題解決。spa

簡單的一個問題,在知道緣由以後。若是不知道緣由呢??(此處有個黑人問號)版本控制

幸虧我知道些npm版本的控制規範,才得已比較早的定位問題並解決之,帶着這份小確幸,從新整理了下npm包管理器的版本管理規範(NPM Version Management Specification)。調試

語義化版本控制規範 SemVer

SemVerSemantic Versioning,語義化版本控制)是Github起草的一個語義化版本號管理模塊,它實現了版本號的解析和比較,規範版本號的格式,它解決了依賴地獄的問題。code

基本規則

語義化版本控制,顧名思義,就是讓版本號更具備語義,能夠傳達出關於軟件自己的一些重要信息而不僅是簡單的一串數字。

基本版本格式

1
主版本號(Major).次版本號(Minor).修訂號(Patch)

每一個部分都爲整數(>=0),按照遞增的規則改變。

版本號遞增規則

  • 主版本號(Major):當你作了不兼容的API修改
  • 次版本號(Minor):當你作了向下兼容的功能性新增
  • 修訂號(Patch):當你作了向下兼容的問題修正
  • 先行版本號版本編譯信息能夠加到基本版本格式的後面,做爲延伸
    • 先行版本號由首位的鏈接號」-「、標識符號(由ASCII碼的英文數字和鏈接號標識符[0-9A-Za-z-]組成)、句點」.「組成。如1.0.0-alpha、1.0.0-alpha.一、1.0.0-0.3.七、1.0.0-x.7.z.92。先行版的優先級低於相關聯的標準版本
    • 版本編譯信息由首位的一個加號和一連串以句點分隔的標識符號(由ASCII碼的英文數字和鏈接號標識符[0-9A-Za-z-]組成)組成。如1.0.0-alpha+00一、1.0.0+20130313144700、1.0.0-beta+exp.sha.5114f85。判斷版本優先層級時,版本編譯信息能夠被忽略

如何比較版本高低

判斷優先層級時,必須把版本依序拆分爲主版本號、次版本號、修訂號及先行版本號後進行比較。由左到右依次比較每一個標識符號,第一個差別值用來決定優先層級(其中字母鏈接號以ASCII排序進行比較、其餘都相同時欄位多的先行版本號優先級較高)。如:

1
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0 < 2.0.0 < 2.1.0 < 2.1.1。

 

範圍規則

<空>

鎖定版本號

  • 1.0.0: 鎖定了版本只能爲1.0.0

<、<=、>、>=、=

指定版本範圍,甚至能夠經過||組合多個比較器

  • =1.2.7 <1.3.0中包括1.2.71.2.81.2.99等等,但不包括1.2.61.3.0 或1.1.0等等
  • 1.2.7 || >=1.2.9 <2.0.0中包括1.2.71.2.91.4.6等等,但不包括1.2.82.0.0等等

-

連字符表示版本號範圍,表示的是一個閉區間

  • 1.2.3 - 2.3.4 至關於 >=1.2.3和 <=2.3.4

x、X、*

能夠替代主版本號.次版本號.修訂號三段中任意一段,表示該位置版本號沒有限制;另外缺省三段中任意一段與用xX*替換該段效果相同

  • * 至關於 >=0.0.0,表示任何版本號
  • 1.X1.x 至關於 >=1.0.0 <2.0.0,匹配到主版本號
  • 1.2.* 至關於 >=1.2.0 <1.3.0,匹配到主版本號和次版本號
  • ""(空字符串) 至關於 * ,即至關於 >=0.0.0
  • 1 至關於 1.x.x,即至關於 >=1.0.0 <2.0.0
  • 1.2 至關於 1.2.x,即至關於 >=1.2.0 <1.3.0

~

容許小版本迭代

  • 若是有缺省值,缺省部分任意迭代;
  • 若是沒有缺省值,只容許補丁即修訂號(Patch)的迭代

eg.:

  • ~1.2.3>=1.2.3 <1.3.0
  • ~1.2>=1.2.0 < 1.3.0(至關於1.2.x
  • ~1>=1.0.0 <2.0.0(至關於1.x
  • ~0.2.3>=0.2.3 <0.3.0
  • ~0.2>=0.2.0 <0.3.0(至關於0.2.x
  • ~0>=0.0.0 <1.0.0(至關於0.x
  • ~1.2.3-beta.2>=1.2.3-beta.2 <1.3.0(注意,在1.2.3版本中,容許使用大於等於beta.2的先行版本號,而除1.2.3以外的版本號容許使用先行版本號,因此此處1.2.3-beta.4是容許的,而1.2.4-beta.2容許的)

^

容許大版本迭代

  • 容許從左到右的第一段不爲0那一版本位+1迭代(左閉右開);
  • 若是有缺省值,且缺省值以前沒有不爲0的版本位,則容許缺省值的一位版本+1迭代

eg.:

  • ^1.2.3>=1.2.3 <2.0.0
  • ^0.2.3>=0.2.3 <0.3.0
  • ^0.0.3>=0.0.3 <0.0.4
  • ^1.2.x>=1.2.0 <2.0.0
  • ^0.0.x>=0.0.0 <0.1.0
  • ^0.0>=0.0.0 <0.1.0
  • ^1.x>=1.0.0 <2.0.0
  • ^0.x>=0.0.0 <1.0.0
  • ^1.2.3-beta.2>=1.2.3-beta.2 <2.0.0(注意,在1.2.3版本中,容許使用大於等於beta.2的先行版本號,而除了1.2.3以外的版本號不容許使用先行版本號,因此此處1.2.3-beta.4是容許的,而1.2.4-beta.2是不容許的);
  • ^0.0.3-beta>=0.0.3-beta <0.0.4(同上,此處0.0.3-pr.2是容許的)

鎖定(控制)版本

看到這,聰明的你必定想到了package-lock.json或是yarn.lock

npm的版本>=5.1的時候,package-lock.json文件是自動打開的,意味着會自動生成,
package-lock.json官方文檔)能夠理解爲/node_modules文件夾內容的json映射,並可以感知npm的安裝/升級/卸載的操做。能夠保證在不一樣的環境下安裝的包版本保持一致。聽上去很不錯哈,實際使用中,大部分它的表現確實不錯,但是如上述問題:我手動修改了package.json文件內依賴的版本,package-lock.json就沒那麼聰明(至少目前是,將來會不會變聰明就不可知了),且不會變化。因而BOOOOOOM~~~~

SO

若是你真的想保證你的包版本在各個環境都是同樣的話,請修改下package.json中的依賴,去掉默認前面的^,固然這樣的話,你就無法自動享受依賴包小版本的修復了,問題來了,在什麼狀況下選擇哪種呢?

  • 在依賴包嚴格按照版本規範來開發的,你可使用^來享受包的最新功能和修復。這也是推薦的。
  • 在你不可知或已知依賴包不是那麼規範的狀況下,或許它在一個小版本(patch)作出不兼容更改(不兼容更改在beta等先行版本中必定[墨菲定律]會發生),那麼這個時候,你應該把這個依賴包的版本在package.json上鎖住版本,而不該該把它交給package-lock.json來處理
  • 記住一點,絕對不要在生成環境下使用beta等先行版本依賴包,由於若是那是你的私有項目,它會在將來的某一刻坑害了你,若是這是你的共有項目,那麼,它必定會在將來的某一刻對你的全部用戶作出致命的坑害行爲!(beta包就是不負責任的流氓包,玩覺爽就好 ^o^)

最後:rm -rf node_modules/ && npm install大法在你使用package-lock的狀況下,請更換爲:rm -rf node_modules && rm -rf package-lock.json && npm install

相關文章
相關標籤/搜索