常規的開發,常規的代碼,不動如山的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 |
- "babel-runtime": "^6.9.2" |
常規rm -rf node_modules && cnpm install
,小段時間的等待以後,發現錯誤並無消失,奇了怪了~~框架
繼續查看依賴包的依賴包,發現它要7.0.0-beta.41
,而在個人node_modules/
黑洞裏的@babel/runtime
卻安裝的是7.0.0
版本,Bingo,問題找到了,鎖個版本,修改以下:ui
1 |
- "@babel/runtime": "^7.0.0-beta.41" |
常規rm -rf node_modules && cnpm install
以後,問題消失了,部署跑CI瞧一下,問題解決。spa
簡單的一個問題,在知道緣由以後。若是不知道緣由呢??(此處有個黑人問號)版本控制
幸虧我知道些npm
版本的控制規範,才得已比較早的定位問題並解決之,帶着這份小確幸,從新整理了下npm
包管理器的版本管理規範(NPM Version Management Specification)。調試
SemVer
(Semantic Versioning,語義化版本控制)是Github起草的一個語義化版本號管理模塊,它實現了版本號的解析和比較,規範版本號的格式,它解決了依賴地獄的問題。code
語義化版本控制,顧名思義,就是讓版本號更具備語義,能夠傳達出關於軟件自己的一些重要信息而不僅是簡單的一串數字。
1 |
主版本號(Major).次版本號(Minor).修訂號(Patch) |
每一個部分都爲整數(>=0
),按照遞增的規則改變。
基本版本格式
的後面,做爲延伸
判斷優先層級時,必須把版本依序拆分爲主版本號、次版本號、修訂號及先行版本號後進行比較。由左到右依次比較每一個標識符號,第一個差別值用來決定優先層級(其中字母鏈接號以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.7
、1.2.8
、1.2.99
等等,但不包括1.2.6
、1.3.0
或1.1.0
等等1.2.7 || >=1.2.9 <2.0.0
中包括1.2.7
、1.2.9
、1.4.6
等等,但不包括1.2.8
或2.0.0
等等連字符表示版本號範圍,表示的是一個閉區間
1.2.3 - 2.3.4
至關於 >=1.2.3
和 <=2.3.4
能夠替代主版本號.次版本號.修訂號
三段中任意一段,表示該位置版本號沒有限制;另外缺省三段中任意一段與用x
、X
或*
替換該段效果相同
*
至關於 >=0.0.0
,表示任何版本號1.X
或1.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
容許小版本迭代
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
迭代(左閉右開);+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
。