你真的知道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

相关文章
相关标签/搜索