LWDW!

Learn the work from doing the work🍺

使用Github Actions与CloudFlare Pages优化博客上线流程
Posted on 2023-02-14

在之前的文章你的静态博客,何必是hexo中,我大概介绍了如何搭建一个个人静态博客,但并没有涉及要如何将其上线。

我个人的首选方案是Github Pages,因为它免费,且域名直观。

在最初的时候,要发布一篇新的博客(或者做一些功能更新),我要手动做以下几步工作:

  1. 在博客仓库(<username>.github.io)切出一个本地新分支;
  2. 在分支上完成博客内容的编写;
  3. 本地运行yarn export构建,生成/docs目录(github pages只允许指定目录为根目录或docs目录);
  4. 将更新过的代码推上远端分支;
  5. 发起PR;
  6. 合并PR;
  7. 等待Github Pages重新部署,去线上验证博客是否更新成功;

在多次不断的重复以上操作后,我意识到了几个问题:

  1. 我经常忘记本地export构建,因为启动dev环境是不需要这一步的;
  2. 博客仓库同时包含了源代码与构建产物代码,如果fork&clone的话,构建产物代码其实是完全没有用的;
  3. 我只有在合并了main分支后才能验证线上博客是否更新成功。如果发生了本地环境没有出现的问题,那就意味着我的线上生产环境崩掉了;

这种情形下,引入一些CI/CD工具实现自动触发线上构建部署是常见的解决方案。我将会介绍Github Actions以及CloudFlare Pages,看看这两个免费服务可以帮我们实现怎样的自动化。

【剧透】最终实现如下:

优化博客部署.png

Github Actions

介绍它的文章很多,因此我不打算展开。直接说它的特点:

  1. 它可以被各种各样的Github操作自动触发——比如新建分支、open PR、push到某个分支,也支持通过Github API手动触发(workflow_dispatch
  2. Github维护了一个Action市场,开发者可以使用社区贡献的Action而无需自己重新手写各种常用功能。比如获取当前的分支、指定node版本、将指定目录推送到Amazon S3。

以我将博客推送到Github Pages的workflow为例:

# .github/workflows/production.yml
# 所有的workflow必须放在.github/workflows目录下才能被识别,文件名会作为该workflow的名称

name: Deploy for production

# on指定了该workflow的触发时机
# 这里是指定在main分支有更新时触发(直接push或者merge进main分支都会触发该时间)
on:
  push:
    branches:
      - main

jobs:
  # job id
  production:
    # runs-on指定了运行任务的机器类型,值得一提的是,我们可以使用自己的机器(比如需要支持内网环境),更多可以去了解“self-hosted runner”
    runs-on: ubuntu-latest
    # environment指的就是仓库设置中 Actions secrets and variables 对应的environment,用于区分变量环境
    environment: production

    # steps就是每个job具体的步骤
    steps:
      # uses代表了这里使用了一个社区贡献的action
      # checkout到指定分支
      - uses: actions/checkout@v3
        with:
          ref: main

      # 指定node版本
      - uses: actions/setup-node@v3
        with:
          node-version: 16

      # yarn install
      - uses: borales/actions-yarn@v4
        name: yarn install
        with:
          cmd: install

      # yarn export
      - uses: borales/actions-yarn@v4
        name: yarn export
        with:
          cmd: export

      # 将上一步的构建目录推动到指定仓库的指定分支
      - name: Pushes to the blog github pages
        uses: cpina/github-action-push-to-another-repository@main
        env:
          # secrets在仓库settings中进行设置好,在对应的环境便可读取
          API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }}
        with:
          source-directory: 'docs'
          destination-github-username: 'B-sirius'
          destination-repository-name: 'b-sirius.github.io'
          target-branch: main

有了这样一个自动触发的工作流后,我便拆分出了博客源代码仓库。每次源代码仓库的main分支更新时,Github Actions会自动去进行构建,并将构建结果push到Github Pages使用的仓库b-sirius.github.io的main分支。而Github Pages也会在main更新时,自动触发部署,更新线上页面。于是我之前提到的痛点的前两个,就都解决了。

CloudFlare Pages

于是我还剩下一个问题:如何支持测试(preview)环境?对于任何应用来说,在本地验证与生产环境发布之间,至少还需要在测试环境验证一次。Github Pages目前还没有对preview环境的官方支持(尽管应该是在进展之中),所以我个人选择了一个简单的方案:再使用一家pages服务,如CloudFlare Pages、Vercel。他们二者都与Git有很好的集成,以下将以CloudFlare Pages为例。

注册登录关联git仓库这些都没什么好说的,都是固定流程,在这些绑定完成后,我们就需要去做一些具体的设置了。

默认情况下,CloudFlare Pages会为main分支自动部署production环境,对所有其余分支自动部署preview环境,后者正好就满足了我们的需要,而前者我不需要,于是将其设置将其关闭。

分支部署

在构建设置中,其实只要指定构建命令与用于上传的构建目录,这部分的配置自然上面的github workflow其实是一模一样的。

构建设置

有一个小细节是,在github workflow中我们指定了node版本,CloudFlare Pages也支持这一点,通过环境变量的方式,你可以在这里看到更多支持的环境变量

指定node版本

总结

于是,我们就实现了这样一个简单却实用的CI/CD流水线。可以看出:

  1. Github Actions其实是一个非常灵活的hook工具,可以去自定义触发各种各样有趣的任务(类似的服务还有Amazon Lambda);
  2. Github Pages是一个纯粹的静态站点托管服务,上传静态站点,它就呈现;
  3. CloudFlare Pages和Vercel也是静态站点托管服务,但是它们更加注重与其他平台的集成,并通过低码的方式去完成简单的构建部署以及呈现;

最终,整个博客部署的步骤如下,只有虚线的关键卡点步骤是手动操作,而其余的工作都会自动完成,很方便吧。

优化博客部署.png