不熟悉 jamstack 的朋友可以先看一下这篇文章 什么是 jamstack
笔者本来想写一篇 Jamstack 实战,技术上主要是以 SSG
+ COS
+ CDN
+ Serverless Framework
+ GitHub Actions
来实现的
然而发现内容有点多,主要分为以下几块:
Serverless Components
website
组件与 其他的后台服务组件GitHub Actions
做持续集成感觉每一个都可以好好的讲讲,都写在一篇文章里,就像蜻蜓点水
故此篇文章,主要介绍的是其中的 CI/CD
部分,即 Serverless Framework
如何使用 GitHub Actions
进行持续化集成
SSG
: 任意的静态网站生成框架 or Raw Html 都可以,笔者在此使用的是 Nuxt.js
, 当然 Next.js
, Gatsby
都是非常优秀的选择,不需要灵活做自定义的,也可以去选择像 Hexo
, VuePress
这类的框架
COS
: 静态网站的源站,腾讯云对象存储
CDN
: 腾讯云的内容分发网络
Serverless Framework
: 在国内可以直接使用 tencent-website
组件,去快速部署和管理我们的 spa/ssg
网站,它也能够对我们的 COS
和 CDN
进行管理。 后台服务也可以使用其他的组件进行部署和管理。
GitHub Actions
: 功能强大,在这里暂且让它负责 CI/CD
的工作
首先,从普通部署的视角看起
本地的前端静态网站是如何进行部署的呢?
我们把步骤拆解一下:
COS
并设置为静态网站,同时指定它的 history fallback
CDN
加速域名,假如已经设置完成,则再次部署时需要去刷新节点,让变更的资源强制过期这几步,映射到我们技术栈的代码中,实际上就做 2 件事
nuxt generate
和 serverless deploy
接下来顺着刚刚的思路,开始想象一个 干净的 的 linux docker
容器中,需要哪些前置条件来支撑部署这个行为呢?
显然,nodejs
环境是必须安装的,serverless framework
也是需要的, 而 yarn
就看个人喜好了
笔者个人比较喜欢使用 yarn.lock
的 文件 hash 值作为 cache key 的一部分,于是 yarn
在此处我也安装了
于是就很容易写出以下的流程:
setup-node
// 限定一下 yarn 的版本
npm install -g yarn@^1.x
// 安装依赖包 npm ci 同理
yarn --prod
yarn add -D @serverless/components
// 生成与部署 npx 同理
yarn generate
yarn components deploy
这里为什么安装了
@serverless/components
可以见 @serverless/components 代码简析 这篇文章
然而,按照这个流程写 Github Actions 的 Yaml 还是行不通的
因为容器内的 serverless framework
,缺少云厂商的授权
此时呢,就可以把我们的 TENCENT_SECRET_ID
和 TENCENT_SECRET_KEY
写入项目仓库中的 Actions secrets
中
具体操作可以使用,仓库的 Settings
> Secrets
> New repository secret
菜单
这种方式可以保护我们的秘钥,见 详细文档
重要:一定要保护好我们的秘钥!!!不要显示在 action 的输出里!!!
因为从本质上来说使用 Serverless Framework .env
的部署方式,其实就是环境变量的部署方式
所以我们给 action
中的 env
直接赋值也是可以的,即
- name: Serverless deploy
shell: bash
env:
TENCENT_SECRET_ID: ${{ secrets.TENCENT_SECRET_ID }}
TENCENT_SECRET_KEY: ${{ secrets.TENCENT_SECRET_KEY }}
run: yarn components deploy
然而此时,会发现 去执行 yarn components deploy
部署,还是会部署失败,还提醒我们,需要 serverless login
, 难道我们授权的腾讯云凭证不起作用?
其实并非如此,因为之前做 源码简析 的时候,也说过,国内国外跑的是不同的命令,且请求的也是不同的域名,判断的方式,在部署的时候,主要依靠 isChinaUser
这个方法来区分
我们来看看这个方法都做了什么?
const isChinaUser = () => {
let result;
if (
process.env.SERVERLESS_PLATFORM_VENDOR === 'tencent' ||
process.env.SLS_GEO_LOCATION === 'cn'
) {
result = true;
} else if (process.env.SERVERLESS_PLATFORM_VENDOR === 'aws') {
result = false;
} else {
result = new Intl.DateTimeFormat('en', { timeZoneName: 'long' })
.format()
.includes('China Standard Time');
}
return result;
};
从代码可知,我们可以注入环境变量的方式,来改变 isChinaUser
的判断逻辑结果,而且因为 Github 的容器啊,默认时区其实都是 UTC,所以会导致Intl.DateTimeFormat
这种判断失败。
那么就简单了,我们只需要部署时,在 env
中加一行 SERVERLESS_PLATFORM_VENDOR: tencent
env:
TENCENT_SECRET_ID: ${{ secrets.TENCENT_SECRET_ID }}
TENCENT_SECRET_KEY: ${{ secrets.TENCENT_SECRET_KEY }}
SERVERLESS_PLATFORM_VENDOR: tencent
就可以顺利的部署了成功了
我们可以利用 actions/cache@v2
把 yarn cache dir
中的包给缓存起来
这样能够大大加速 yarn 安装包的一个时间
缓存的 key
,可以利用提交的 yarn.lock
文件的 hash
值组合而成的一个键,package-lock.json
同理
具体配置项见 actions/cache
由于 容器默认时区是 UTC, 而中国属于 东八区 UTC+8
, 也就是 Asia/Shanghai
, 假如我们不预先设置为这个时区,就会导致在构建打包时,nodejs 的时间产生问题,进而影响到我们打包工具。
这里就可以使用 szenius/set-timezone@v1.0
这个 Action
了
只需要把 runner os
的时区设置为 Asia/Shanghai
, 打包时时区问题就解决了
其实所有的 Serverless Framework
的组件,都可以通过这种方式,进行持续化集成。
这块我这篇文章,写的还是比较入门的,项目场景也很简单。
如果有其他更好的解决方案,也欢迎一起进行探讨交流。