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


NPM Version Management Specification

來源

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

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

 

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

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 未發現錯誤原因以及真正的解決辦法,TnT

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

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,問題找到了,鎖個版本,修改如下:

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

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

簡單的一個問題,在知道原因之后。如果不知道原因呢??(此處有個黑人問號)

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

語義化版本控制規范 SemVer

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

基本規則

語義化版本控制,顧名思義,就是讓版本號更具有語義,可以傳達出關於軟件本身的一些重要信息而不只是簡單的一串數字。

基本版本格式

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

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

版本號遞增規則

  • 主版本號(Major):當你做了不兼容的API修改
  • 次版本號(Minor):當你做了向下兼容的功能性新增
  • 修訂號(Patch):當你做了向下兼容的問題修正
  • 先行版本號版本編譯信息可以加到基本版本格式的后面,作為延伸
    • 先行版本號由首位的連接號”-“、標識符號(由ASCII碼的英文數字和連接號標識符[0-9A-Za-z-]組成)、句點”.“組成。如1.0.0-alpha、1.0.0-alpha.1、1.0.0-0.3.7、1.0.0-x.7.z.92。先行版的優先級低於相關聯的標准版本
    • 版本編譯信息由首位的一個加號和一連串以句點分隔的標識符號(由ASCII碼的英文數字和連接號標識符[0-9A-Za-z-]組成)組成。如1.0.0-alpha+001、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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM