📖阅读本文,你将:
- 深入理解
npm
正在使用的semver
语义版本号标准。 - 学会使用一种版本号管理工具。
一、如果 没有了版本 ?
版本是组件的 核心属性 。
让我们试想一下,如果没有版本 ,前端开发的场景会变成怎样什么样?
开始脑补:(没有了 版本 的前端开发)
-
npm install
永远会安装最新版本的依赖,上一秒正常运行的项目,在 npm install
后突然发现 api
失效了。install
变成了一个高危操作。 -
vue.js
的 issues
区里充满了这样的帖子:“无耻老贼,你怎么又把 alpha
版本发到 npm
上了?害我失业!” -
vue.js
的官网上常年挂着一堆下载链接:“2022年7月18日下载包”、“2022年7月19日下载包”、“2022年7月19日紧急修复版”…… - 办公室里,A同事对B同事喊了一声:“王哥,你那儿有上个月25号的vue版本不?用U盘拷我一分呗……”
- 很多程序员下载
vue.js
选择去某“华军软件”下载,结果被捆绑了 360
全家桶…… - 掘金社区天天有人发帖:“跪求支持
xxxx
的老版 vue
……” - 掘金网友 “摸鱼的春哥” 打包出售近三年所有发布过的
vue.js dist
文件,实现财务自由……
emmm……画风越来越奇怪,不禁让我们感慨,现如今的 npm
版本机制实在是太重要了,如果没有它,我们会分分钟退回刀耕火种的岁月。
那么,npm
的版本究竟是怎么玩转的呢?你又是否已经完全理解了 npm
版本所代表的含义呢?
不妨试试回答以下几个问题:
-
^1.1.0
和~1.1.0
的区别是什么? -
1.01.02
是否合法? -
1.0.1
、1.0.1-alpha.2
、1.0.1-rc.2
这三个版本号由大到小的顺序是什么? -
vue@latest
应该命中哪个版本?由谁决定?那么vue@v2-beta
呢?
如果回答不上来,或者还心有疑虑,那么不妨继续看下去,寻找答案。
二、什么是 semver
?
我们常说的 semver
分为两个维度:
- 维度一:它是一套跨语言的语义化版本号标准。
标准地址:semver.org/lang/zh-CN/ - 维度二:是基于这套标准的实现,比如
node-semver
(npm
就依赖着它)。 npm
的版本策略,几乎全部都由它进行控制 。
npmjs:www.npmjs.com/package/sem…github:github.com/npm/node-se…
三、semver
标准
semver
有一套关于版本号的语义标准。
3.1 标准版本号(Major.Minor.Patch)
比如 16.7.1
这个简单的版本号,其实是由三个部分组成的:
- 16 是它的
Major
,主版本号,通常只有在重构、API不向下兼容时才会进行升级。 - 7 是它的
Minor
, 次版本号,通常在增加向下兼容新特性时升级此版本号。 - 1 是它的
Patch
,修订号,通常在发布向下兼容的问题修复时更新。
在 npm
指令集中,你可以通过指令来修改版本号,假设你现有一个 1.2.3
版本的项目。
通过执行指令,项目版本会直接发生变化
npm version major
# 1.2.3 => 2.2.3
npm version minor
# 1.2.3 => 1.3.3
npm version patch
# 1.2.3 => 1.2.4
3.2 先行版本号(pre-release)
上一节的 “标准版本号” 通常是指正式发布的版本。
但开发过程,往往还伴随着 内测、 公测、 生产候选 等种版本形式。
于是,在 “标准版本号” 的基础上又增加了一个新的版本号区域:pre-release
区。
如图所示。
先行版本号的典型格式是 -alpha.1
这样的形式,它由 一个短横线 + 一个字符串组成。
- 短横线:
-
- 字符串:由大小写的字母、数字、句点组成。
因此,以下先行版本号都是合法的:
- 16.7.1-1
- 16.7.1-a.2
- 16.7.1-a.c
有一个经常被人弄错的知识点:16.7.1-alpha.1
的版本号是 小于 16.7.1
。
因为 16.7.1-alpha.1
是 16.7.1
的内测版本,所以它一定是小于正式版本的。
3.3 先行版本的约定命名
虽然 16.7.1-1
、16.7.1-a.2
也是合法的 先行版本号 ,但大家一般不这么玩,倒不是规范不允许这么玩,而是它们的 语义化不优秀。
因而,大家约定俗成了三个常见的 先行命名 方式,他们是:
-
16.7.1-alpha.1
:16.7.1
内测的第一个版本 -
16.7.1-beta.1
:16.7.1
灰度测试的第一个版本 -
16.7.1-rc.1
:16.7.1
生产候选的第一个版本
因为 r
> b
> a
,所以这个约定实际也能代表上线的先后顺序:
16.7.1-alpha.1
< 16.7.1-beta.1
< 16.7.1-rc.1
< 16.7.1
。
同样的,npm version release
可以帮助你递增 先行版本号。
四、npm
的版本匹配策略
4.1 模糊匹配符
npm
工程们并不永远精准的确认自己依赖哪一个版本,因为这会给你的应用带来过高的体积负荷。
假想一下:
-
A
组件声明它依赖lodash@1.0.1
版本; -
B
组件声明它依赖lodash@1.0.2
版本; -
C
组件声明它依赖lodash@1.0.3
版本;
这样一来,你的工程里就不得不安装三个相近的版本,甚至导致你最终的 dist
文件里被打包了三份 lodash
。
这显然并不划算,更优秀的玩法是:只要 lodash
的版本号大于等于 1.0.1
,且小于 2.0.0
都是满足需求的,因此组件们可以选择最大满足需求的范围来声明依赖版本。如:
三个库都只做如下声明:
依赖 lodash@^1.0.1
那么,程序就会找到 lodash
1.x版本中最新的一个版本,仅仅安装一次,也不会对后期构建产生冗余。
这种语法,就是 模糊匹配。
-
^1.0.1
、1
、1.x
代表了可以命中主版本一致、但更新的版本号。 -
~1.0.1
、1.1
、1.1.x
代表了可以命中主版本、次版本一致、但更新的版本号。 -
*
和x
可以命中一切新发布的版本号。
4.2 dist-tag
和版本号
当你使用下面这条命令时,它应该命中哪个版本?
npm install vue@latest
# 或者换一句
从语义上,我们可以大抵理解:latest
是当前最新稳定版、next
则是最新下一代版本。
但它们又是怎么生效的呢?
这涉及到了一个 npm
指令:dist-tag
。
简单说:它可以支持你取一些 “别名标签”,并将它们和某个版本号关联起来。
比如,vue
这个众所周知的库就有9个 dist-tag
:
-
beta
: 灰度测试版本,当前匹配3.2.34-beta.1
-
latest
:3.2.37
最新正式版 -
next
:3.2.36
下一代版本(在vue4出来前暂时没啥用了) -
preview
:3.0.3
预览版 -
csp
:内容安全版本 -
legacy
:历史稳定版 -
v2-alpha
:vue2
的内测版 -
v2-beta
:vue2
的灰度版 -
v2-latest
:vue2
的最新正式版
因此,当你撰写自己的组件库时,别忘了通过以下命令标注出该工程的 latest
版本哦:
npm dist-tag add i-love-chunge@1.0.0 latest
这样一来,i-love-chunge@latest
就能命中 1.0.0
版本啦~
五、semver
标准的优秀实现:node-semver
库
5.1 node-semver
有什么用
用处很多:
- 校验一个版本号是否合法。
比如 1.2.3
合法;a.b.c
就不合法。 - 比较两个版本号之间的大小。
比如 1.2.3
就小于 9.8.7
- 校验一个版本号是否命中了一个 “版本匹配规则”。
比如 1.2.3
显然命中了 ^1.2.0
的规则。 - 给一堆版本号进行排序
- 对一个既有版本号进行升版
等等……
可以说,npm
所有关于 “版本号” 的操作逻辑,都可以通过 semver
来进行实现。
5.1 安装
通过 yarn
、npm
等包管理工具都可以轻松安装。
npm install semver
# or
然后通过以下命令进行引入即可:
const semver = require('semver')
5.2 使用
建议自行查看文档:github.com/npm/node-se…
- 校验一个版本号是否合法:
semver.valid('1.2.3') // '1.2.3'
semver.valid('a.b.c') // null
- 清除版本号里一些多余的语句:
semver.clean(' =v1.2.3 ') // '1.2.3'
- 比较版本号的大小
semver.gt('1.2.3', '9.8.7') // false
semver.lt('1.2.3', '9.8.7') // true
因为文档上有,不做赘述,只要理解了 semver
标准,使用 node-semver
库将会非常顺畅。
如果未来你有关于版本号的校验逻辑,别忘了这个库哦~
六、结束语
我是春哥
。
大龄前端打工仔,依然在努力学习。
我的目标是给大家分享最实用、最有用的知识点,希望大家都可以早早下班,并可以飞速完成工作,淡定摸鱼🐟。
你可以在公众号里找到我:前端要摸鱼
。