前端组件库版本管理与自动发布实践

4,600 阅读2分钟

前端组件库的版本管理与自动发布是很有必要的。最近,终于有时间进行了实践。以下是实践总结,以备不时之需。

嗯,对,我们这边都是前端开发自己动手实现手工作坊式CICD。

1. 需求

  1. 组件库的版本号要满足语义化版本 2.0
  2. 要有对应的 Change log
  3. 需要在发布之前进行测试,只有测试通过了才可以发布
  4. 要能够自动部署文档
  5. 在满足条件的情况下,要能够自动发布前端 npm package

2. 痛点

  1. 版本发布时,组件库项目负责人不知道此次具体更新了哪些内容(也有可能是我规划的不好)
  2. 目前只能手动维护 change log, git tag 以及 package.json 中的 version
  3. 测试,文档发布,前端发包都是手动的(重复性体力劳动)

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,大家可以根据自己项目的情况,进行编排。

  1. version check:已经发布过的版本,就不再发布了
  2. 依赖安装
  3. 单元测试
  4. 构建
  5. 文档部署:组件文档网站我们是用 nginx 部署的,因此此步骤只需要把构建出来的文档网站资源,上传到服务器对应位置上即可
  6. 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 进行单元测试,这里记录一些相关的准备工作:

  1. 服务器上需要有 chrome
  2. 服务器上需要有 CHROME_BIN 环境变量
  3. 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. 总结

对于我的日常工作来说,以上方案已经满足了我的需求,解决了我的痛点。在实际实践过程中也学习到了很多东西。希望本篇内容,可以在某些方面帮助到大家。