本节涉及的内容源码可在vue-pro-components c8 分支[1]找到,欢迎 支持!
本文是 基于Vite+AntDesignVue打造业务组件库[2] 专栏第 9 篇文章【在本地和CI/CD中支持npm免登录发布】,专门分享一下如何在 npm 发包时支持免登录发布,并同时支持在本地和CI/CD中操作发布流程。
在组件库技术选型和开发环境搭建[3]这篇文章中,我们简单介绍了怎么把一个包发布到 npm 上,但是执行lerna publish
之前需要先验证登录,因为lerna publish
它背后执行的还是npm publish
,所以首先需要通过 npm 的认证流程。
一个流程中如果要执行登录流程,那么它的自动化程度就不会很高。如何解决这个问题呢?答案是 token,只要我们把 token 通过某个配置告诉 npm,就等同于告诉 npm 我是谁,所以只要这个 token 代表的是我的身份,自然就没必要输入账户密码登录了。
我们先在 npm 网站[4] 中登录,在用户下拉菜单这里能找到创建 token 的入口。
token 有两种,
一种是经典的通用 token,就是不限制使用范围,你名下的任何包/组织都能用这个 token 去管理。但是也大概分几种类型。如果要用在自动化流程中,需要避开双因素(2FA)验证,我们就创建 Automation 类型的 token。
还有一种就是更细粒度的 token,可以把权限控制到过期时间/IP范围/可读可写/包/组织等。
如果你觉得用界面操作很 Low,也可以选择极客风的命令行。npm 提供了创建 token 的命令行,具体见 npm token[5]。
我们创建 token 主要是为了用于发布 npm 包。这个 token 我们可以配置在.npmrc
文件中,对应的 key 是_authToken
。
//registry.npmjs.org/:always-auth=true
//registry.npmjs.org/:_authToken=your npm token
但是.npmrc
文件一般是要提交到仓库中的,而 token 又是一个比较私密的数据,就不适合写死放在 .npmrc 中,此时我们可以使用变量替代,改成这样:
//registry.npmjs.org/:always-auth=true
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
那么这个变量可以从哪里读来呢?我们可以看看 npm 的一篇文档Set the token as an environment variable on the CI/CD server[6]是怎么说的。
The npm cli will replace this value with the contents of the NPM_TOKEN environment variable.
答案是环境变量。这里要考虑 2 种情况,一个是本地化发布,一个是在 CI/CD 中发布。
首先说后面一种情况,在 CI/CD 中发布 npm 包已经有比较标准的方案了,大部分 CI/CD 平台都支持在 yaml 配置文件中指定环境变量,并且支持加密,没有暴露 token 的风险。上述文档中也有提到,关键配置如下:
steps:
- run: |
npm install
- env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
那么关键还是在于前面那种情况,有时候需要在本地发布 npm 包,此时应该怎么办呢?
我首先尝试添加系统环境变量,但是没有立即成功;
我还尝试了dotenv
,虽然dotenv
能加载.env
文件到环境变量中,不过也不太方便。
如果.npmrc
中存在变量NPM_TOKEN
,跑任何npm scripts
,都会去寻找${NPM_TOKEN}
,如果找不到就会报错,而我们不可能给所有脚本都加上dotenv
。
所以如果要在本地发布,一个替代方法是临时手动将.npmrc
的 token 写死,改成:
//registry.npmjs.org/:_authToken=npm_xxxxxxxxxxxxxxxxxx
但是执行 lerna publish 的时候又需要一个干净的 git 状态,如果有 modified files 也不行(因为临时改了 .npmrc 就会导致 git 工作区不干净了)。啊,真难!最理想的办法还是把环境变量给搞定,同时又不能改太多脚本。
最后我发现加系统环境变量其实是有用的,关键是改了后要重新打开 VSCode(之前没有尝试这一步,导致我以为加系统环境变量没有用),否则终端加载不到最新的环境变量,果然还得是重启大法!所以最佳选择是使用变量${NPM_TOKEN}
。
搞定了环境变量后,我们先试试本地 publish 的场景。
考虑到之前用npm login
或者npm adduser
登录过,所以我们需要先退出登录再测试,否则无法确定是否 token 是否真的起了作用。
退出登录命令:
npm logout --registry=https://registry.npmjs.org
接着可以试试lerna publish
或者npm publish
,经测试已经不需要登录就能发布 npm 包了。
在集成构建和发布流程之前,我们参照@vue-pro-components/utils
的构建流程把@vue-pro-components/headless
的构建流程搞定,因为它们本质上都是函数库,打包过程不会有太多差异,抄一抄它不香吗?
同时根据各个包之间的依赖关系,新增一个统一构建的入口buildBatch
,这样就能通过gulp buildBatch
一条命令把所有的构建工作都做了。
继而可以得到一条集成构建和发布流程的命令release
。
"release": "yarn buildBatch && yarn publish:package",
所以只要我们把代码修改完毕,版本号确定之后,就可以执行yarn release
进行发布了。
Github 本身也支持 CI/CD,相关的产品是 Github Actions,所以我们可以直接使用它实现自动化构建和发布流程。
现在市面上有很多 CI/CD 工具,它们虽然在配置上有些差异,但是架构和理念都是相似的,学会使用一个,其他的参考着文档也基本能看得懂。
使用 Github Actions 主要就是写配置文件,我们可以基于官方的一些模板[7]来初始化一个配置文件,这个 Publish Node.js Package 模板就比较合适。
你也可以通过阅读Github Actions 文档[8]来了解更多相关知识。
我们按照模板文件改一改:
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
name: Build and Publish Node.js Package
on:
push:
branches:
- c*
env:
NPM_TOKEN: ${{secrets.NPM_TOKEN}}
jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Dependency
run: yarn install --frozen-lockfile
- name: Build and Publish
run: yarn release
因为这里要用到NPM_TOKEN
变量,我们先到 Settings -> Secrets 中维护好变量。
修改一个版本号测试一下,一个简单版本的 CI/CD 这不就有了吗?
然后可以再加个 Cache 优化一下安装依赖的过程,这可以用到actions/cache@v3[9]。
通过阅读和学习本文内容,我们已经能掌握怎么优雅地发布一个 npm 包,并同时支持了在本地和远程 CI/CD 中进行发布操作。但是我们应该注意到,每次发布都会执行完整的buildBatch
过程,这个有没有必要呢?我想有时候是没有必要的,因为有可能某一个包根本就没修改过,但是每次发布时都执行打包过程就会浪费资源和时间。这里先留个疑问,后面文章接着讲。如果您对我的专栏感兴趣,欢迎您订阅关注本专栏[10],接下来可以一同探讨和交流组件库开发过程中遇到的问题。
[1]
vue-pro-components c8 分支: https://github.com/cumt-robin/vue-pro-components/tree/c8
[2]
基于Vite+AntDesignVue打造业务组件库: https://juejin.cn/column/7140103979697963045
[3]
组件库技术选型和开发环境搭建: https://juejin.cn/post/7153432538046791687#heading-16
[4]
npm 网站: https://www.npmjs.com/
[5]
npm token: https://docs.npmjs.com/cli/v9/commands/npm-token
[6]
Set the token as an environment variable on the CI/CD server: https://docs.npmjs.com/using-private-packages-in-a-ci-cd-workflow#set-the-token-as-an-environment-variable-on-the-cicd-server
[7]
官方的一些模板: https://github.com/cumt-robin/vue-pro-components/actions/new
[8]
Github Actions 文档: https://docs.github.com/en/actions/quickstart
[9]
actions/cache@v3: https://github.com/actions/cache/blob/main/examples.md#node---yarn
[10]
订阅关注本专栏: https://juejin.cn/column/7140103979697963045