📖阅读本文,你将:
- 深入理解
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 分为两个维度:
-
维度一:它是一套跨语言的语义化版本号标准。
-
维度二:是基于这套标准的实现,比如
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
# 或者换一句
npm install vue@next
从语义上,我们可以大抵理解:latest 是当前最新稳定版、next 则是最新下一代版本。
但它们又是怎么生效的呢?
这涉及到了一个 npm 指令:dist-tag。
简单说:它可以支持你取一些 “别名标签”,并将它们和某个版本号关联起来。
比如,vue 这个众所周知的库就有9个 dist-tag:
beta: 灰度测试版本,当前匹配3.2.34-beta.1latest: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
yarn add semver
然后通过以下命令进行引入即可:
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 库将会非常顺畅。
如果未来你有关于版本号的校验逻辑,别忘了这个库哦~
六、结束语
我是春哥。
大龄前端打工仔,依然在努力学习。
我的目标是给大家分享最实用、最有用的知识点,希望大家都可以早早下班,并可以飞速完成工作,淡定摸鱼🐟。
你可以在公众号里找到我:前端要摸鱼。
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。