前端组件库的版本管理与自动发布是很有必要的。最近,终于有时间进行了实践。以下是实践总结,以备不时之需。
嗯,对,我们这边都是前端开发自己动手实现手工作坊式CICD。
1. 需求
- 组件库的版本号要满足语义化版本 2.0
- 要有对应的 Change log
- 需要在发布之前进行测试,只有测试通过了才可以发布
- 要能够自动部署文档
- 在满足条件的情况下,要能够自动发布前端 npm package
2. 痛点
- 版本发布时,组件库项目负责人不知道此次具体更新了哪些内容(也有可能是我规划的不好)
- 目前只能手动维护 change log,
git tag
以及package.json
中的version
- 测试,文档发布,前端发包都是手动的(重复性体力劳动)
3. 解决方案
3.1 使用 standard-version 进行版本管理
使用 standard-version 可以按照语义化版本 2.0
来自动更新 package.json
中的 version
。同时可以自动生成 Change log 以及 git tag
。
在使用 standard-version
之前,需要遵循 Conventional Commit Specifications 来进行标准化的 commit message
编写。这是因为 standard-version
是基于 commit
类型来更新版本号的。规范化 commit message
的编写可以使用 commitizen 来完成。
这里可以查看我翻译的另外一篇文章来获取详细信息。
3.2 使用 Jenkins Pipeline 进行具体的发布工作
Jenkins 是个开源的 CI&CD 软件。想必大家已经很熟悉了,我这里就不多介绍了。Jenkins 的官方文档有中文版,有需要的朋友可以前往查看。
4. 落地
4.1 开发过程中规范化 commit message
可以增加如下 npm script
来方便开发过程中的代码提交:
// package.json
"commit":"git-cz"
4.1.1 结合 husky 进行强制校验
可以结合 husky 来对 commit message
的格式进行强制校验。
在工程中添加 .huskyrc
文件,具体内容如下:
// .huskyrc
{
"hooks": {
"commit-msg": "commitlint -e $GIT_PARAMS"
}
}
在 devDependencies
中添加如下依赖:
// package.json
"@commitlint/cli": "^8.3.5",
"@commitlint/config-conventional": "^8.3.4",
"husky": "3.0.3"
在工程中添加 .commitlintrc
文件,内容如下:
// .commitlintrc
module.exports = {
extends: [
"@commitlint/config-conventional"
],
rules: {
}
};
4.2 在 master 分支上进行版本发布
我们前端组件库代码采取的分支策略基本同 git flow 相同,只不过没有创建专门的 release 分支,是直接在 master 分支上进行版本发布的。
使用 standard-version
进行发布操作。在工程目中我们添加了如下 npm script
方便发布操作:
// package.json
"release": "standard-version --no-verify -t release-"
执行该命令后,会自动更新 package.json
中的 version
, changelog
以及 git tag
。很是方便。
最后将生成的新 tag
推送至远端
(Gitlab),触发 Jenkins Pipeline:
git push --follow-tags origin master
4.3 Jenkins Pipeline
具体的 Gitlab,Jenkins Pipeline 配置我这里就不再详细描述了,网络上关于 Jenkins Pipeline 配置的博文还是很多的,我只把一些关键的决策写出来。(主要是 Jenkins 我自己也很业余,就不误导大家了)
4.3.1 Jenkinsfile
使用 Jenkinsfile 的好处有很多,最主要的是可以跟随项目代码一起进行版本管理。
只不过有一点需要注意,在编写 pipeline 时,难免会用到一些密钥,密码,token 之类的。最好是使用 credentials 避免重要信息泄露。
4.3.2 stages
我这里大致描述一下我的 stages,大家可以根据自己项目的情况,进行编排。
- version check:已经发布过的版本,就不再发布了
- 依赖安装
- 单元测试
- 构建
- 文档部署:组件文档网站我们是用 nginx 部署的,因此此步骤只需要把构建出来的文档网站资源,上传到服务器对应位置上即可
- npm publish
5. 坑
本次实践遇到了很多坑,在此集中记录,希望能够在一定程度上帮助到大家。
5.1 Jenkins 缓存源码
此次实践中遇到了 Jenkins Pipeline 不拉取最新代码的情况。解决办法非常粗暴:在 Pipeline 设置中,Pipeline > Definition > SCM > Additional Behaviours 增加了 Wipe out repository & force clone;
其实这个问题还是源于我对 Jenkins 不熟悉。我相信,这个问题肯定不应该这样解决。
5.2 npm view 命令
在 version check 环节中,我使用了 npm view . versions --json
命令来获取当前 npm 仓储上已经发布过的前端组件库的版本号,用来进行版本号校验,避免相同版本号的包重复发布,覆盖。
我司内部使用 nexus 作为私有 npm 仓储。我估计,应该能够通过 nexus 中的某项配置,避免相同版本号的包重复发布,覆盖的情况。不过,我不是 nexus 管理员,也不熟悉 nexus,所以采取了手动校验的办法。
这里一定不要通过 nexus 的 web 端,进行手动删包操作,有可能会导致 npm view .
命令返回空。具体的原理我没搞清楚,先暂时记录一下。等日后有时间,再回过头来研究。
5.3 在 linux 环境上运行 karma 测试
我们的前端组件库使用 karma 进行单元测试,这里记录一些相关的准备工作:
- 服务器上需要有 chrome
- 服务器上需要有
CHROME_BIN
环境变量 ChromeHeadless
需要以no-sandbox
运行
// karma config
browsers: ['ChromeHeadlessNoSandbox'],
customLaunchers: {
ChromeHeadlessNoSandbox: {
base: 'ChromeHeadless',
flags: ['--no-sandbox']
}
}
5.4 Pipeline Utility Steps Plugin 可以读取 json 文件
Jenkins 的 Pipeline Utility Steps Plugin 可以在 pipeline 中读取 json 文件:
// Jenkinsfile
// 环境变量
environment {
def packageJSON = readJSON file: 'package.json'
VERSION = "${packageJSON.version}"
}
5.5 npm publish 权限问题
在 Jenkins 服务器上执行 npm publish
时需要登录 npm 仓储。解决方法是使用 echo
命令向工程中的 .npmrc
文件直接写入 _authToken
:
# Jenkinsfile
echo -e "\n//ip:port/nexus/repository/npm-snapshots/:_authToken=${NEXUS_NPM_TOKEN}" >> .npmrc
其中 ${NEXUS_NPM_TOKEN}
是使用 Jenkins credentials 获取的:
// Jenkinsfile
// 环境变量
environment {
NEXUS_NPM_TOKEN = credentials('npm-snapshots')
}
这样可以有效防止在项目代码中直接携带 npm _authToken
。
6. 总结
对于我的日常工作来说,以上方案已经满足了我的需求,解决了我的痛点。在实际实践过程中也学习到了很多东西。希望本篇内容,可以在某些方面帮助到大家。