关于版本语义化及个人的一点浅薄认识和实践

1. 版本语义化

1.1 版本号构成

开发中离不开安装各种 npm 包,大家应该都知道是这样的版本号: x.y.z ,它遵从以下语义化规则:

  • major
    即上面的x,代表主版本(API 不兼容的版本,有发生较大的变更)
    注意:大版本不向后兼容
  • minor
    即上面的y,代表次版本(比如增加某功能,向后兼容)
  • patch
    即上面的z,代表补丁版本(比如修复小问题,向后兼容的小修改)

1.2 升级版本号并打标

1.2.1 NPM 版本升级命令

通过以下命令,可以按照版本语义化规则自动升级版本号

# 升级补丁版本号
npm version patch

# 升级次版本号
npm version minor

# 升级主版本号
npm version major

1.2.2 升级过程和作用

执行上面的升级版本号脚本命令,会为你完成以下工作:

  • 修改版本号
    找到 package.jsonpackage-lock.json ,根据语义化规则,相应地增加版本号
  • 提交这次修改
    相当于执行了 git addgit commit ,提交的 log message (comment) 就是版本号
  • 给这次升级版本打标
    相当于执行了 git tag

注意:这次修改版本号的提交和打标都没有 push 到远程

这样,每次升级版本号的时候,都是一次单独的提交(自动修改版本号),
跟其他的功能特性开发以及 bug 修复自动区分开来,git 使用上更加合理规范。

1.2.3 可以用指定 tag 发版

如果是开发的前端项目,而且通过 jenkins 发版,就可以通过指定 tag 做到精细化发版。
使用 Git Parameter 插件,添加一个 Parameter TypeTag 的参数, Build with Parameters
当然前提是记得将 tag 推送到远程上,例如:

# 将名为 v0.1.0 的 tag 推送到远程
git push origin v0.1.0

1.2.4 脚本例

以下为编译打包一个 npm 包然后升号发布的简单例子,
package.json中:

  "scripts": {
    "serve": "vue-cli-service serve",
    "build:lib": "vue-cli-service build --target lib --name my-lib-name ./src/main.prod.js",
    "publish:patch": "npm run build:lib && npm version patch && npm publish",
    "publish:minor": "npm run build:lib && npm version minor && npm publish",
    "publish:major": "npm run build:lib && npm version major && npm publish",
    "lint": "vue-cli-service lint"
  },

根据是要升级主版本,还是大版本或者小版本,来执行不同的命令:

# 当需要升级补丁版本
npm run publish:patch

# 当需要升级次版本
npm run publish:minor

# 当需要升级主版本
npm run publish:major

在此之前,可能在开发该版本之前,已经拉了对应的分支,这里只讲了版本号以及 tag 打标,没有涉及到分支管理。
还有可以集成进去编译打包完成后同步更新到 demo 示例,不是本文关注点,略去。

1.2.5 补充

当需要修改时如何手动修改 tag

  • 删除本地的 tag
   git tag -d tag-name
  • 删除远程上的 tag
   git push origin :refs/tags/tag-name
  • 修改并提交代码
  • 手动打标当前版本的 tag
   git tag v2.0.1 -m "comment"
  • 推送标签到远程
   # 推送单个tag
   git push origin tag-name
   
   # 推送全部tag
   git push origin --tags

   # 当 tag 名与分支名相同时
   git push origin refs/heads/v0.1.0:refs/heads/v0.1.0

通常不建议发版后再修改!
如果发版后发现有问题,是要在新的版本上修改并发布,有问题的版本上作出相关说明,告诉使用者要注意这个版本上存在的问题,并建议升级到新版本。

2. NPM 的规则

2.1 关于默认规则

npm install some-package -S 安装一个 npm 包,
默认安装后package.json中的依赖项会是这样的:

"some-library-package": "^1.2.3"

版本号数字前面的 ^ 代表如果有主版本以外的更新都被允许安装,比如:

最新版本 可否安装
1.2.4 OK
1.3.0 OK
2.0.0 NG

2.2 关于锁定版本

根据上文 2.1 中提到的规则,会造成一个问题,就是团队不同人拉取代码后,npm install 之后,安装的版本不一致,环境不一致就会造成,无法保证在每个人的机器上代码都能正常运行。

2.2.1 YARN

npm 是安装 nodejs 自带的官方包管理器,由于 npm 存在的一些问题,大厂们能力强,可造轮子可造车,于是想办法自己改进,就有了 yarn。

yarn 是 Facebook 贡献的 javascript 包管理器,一经问世,凭借着稳定可靠快速(可以并行安装)等特点受到广泛好评并推广使用。

其中它的一个特点是,可以生成 yarn.lock 文件,以锁定依赖包的版本,团队其他人拉取代码后,也可以根据 lock 文件安装相同的版本。

2.2.2 NPM 的改进

npm 也是得到问题反馈,看到 yarn 的特点,于是,在 5.x.x 之后也有了 package-lock.json ,并以此为安装依据保障不同成员安装相同版本。
不过,lock 文件优先级大于 package.json ,并没想象中那么"香":

  • 当想要升级依赖包的时候
    修改了 package.json 中依赖的版本号,安装却是按 lock 文件里的,被固定住了
  • 当增加依赖包的时候
    package.json 中增加了一项依赖,却因为 lock 文件里并没有,所以安装不上

这并不符合人们使用 package-lock.json 的预期,这个问题在 5.1.0 之后得到了修复。
优先级:

package.json > package-lock.json

2.2.3 npm/yarn 要不要使用 lock

我个人一直是使用 npm 的,并没有使用 yarn,
倒不是因为觉得 yarn 不好,而是反正有国内镜像源,
使用 npm 就足够了,而且公司有内部包管理器,
yarn 有的优秀特性,npm 也可以吸收借鉴,
它本身也是在不断迭代更新变得更好。
(比如 lock 文件,比如 workspace)

个人建议是不要使用 lock 文件,
团队中个人习惯不同,有使用 npm 的,也有使用 yarn 的,
有时候就会造成 package-lock.jsonyarn.lock 的冲突。

另外,使用了 lock 文件锁定版本的话,
依赖的公司内部组件包,不管是否修改频繁,
都得手动修改 package.json 的版本号才行,
这就造成繁琐的非必要耦合。
(最好是 package-lock.json 也同时修改 -> 本地安装一下)

个人实践

了解了以上这么多,我个人在开发公司内业务组件 npm 包的时候,是这么做的:

3.1 配置 NPM 安装规则

在上文的 2.1 中,提到了默认规则,这个规则是可以改的:

npm config set save-prefix='~'

或者在.npmrc 的配置文件中设置如下:

save-prefix = "~"

推荐使用后者,这样就不必每个团队成员修改配置了,而是把配置写在了项目里。

~ 与 默认的 ^ 的差别在于:(以 js-cookie 1.8.2 为例)

说明
^1.8.2 主版本以外的升级都适用(次版本和补丁版本) 1.8.5 OK
1.9.1 OK
2.0.1 NG
~1.8.2 仅适用补丁版本 1.8.5 OK
1.9.1 NG
2.0.1 NG
1.8.2 固定版本 1.8.5 NG
1.9.1 NG
2.0.1 NG

安装指定版本:

npm install js-cookie@1.8.2

当首次安装依赖包时指定了固定版本,无需 lcok 文件就达到锁定版本的效果;只是享受更新(如 bug-fix)不方便了。

3.2 配置禁用 lock 文件

个人不建议使用 lock 文件来锁定版本,而是根据语义化安装最新的可升级版本。

  • 避免 lock 文件冲突
  • 免除手动更改依赖的版本号
  • 避免使用旧版本即保证已修复问题能够及时提供到使用者

不想使用 lock 文件,可以手动删除,并添加到 .gitignore 中;
更是可以直接禁用 lock 文件功能:

npm config set package-lock false

或者在.npmrc 的配置文件中设置如下:

package-lock = false

通过以上配置禁用之后,就不会在安装时生成 lock 文件,也就不用删除它并添加 .gitignore 了。

推荐使用后者,原因同上

综上,配置.npmrc为:

save-prefix = "~"
package-lock = false

3.3 总结原则

项目中升级依赖包的原则即是,

  • 补丁版本,发版自动升
  • 次版本添加特性,按需手动升
  • 主版本 API 不兼容的变更,按需手动升,一般不升

欢迎交流指正

--END--

posted on 2021-01-01 02:05  CoderMonkey  阅读(141)  评论(0编辑  收藏  举报

导航