AsciiDoc 转 HTML 部署至 Cloudflare Pages 自动化

先上效果:https://wedrinkfun-privacy-policy.pages.dev/

背景

我的 APP「微醺坊」要上架了,需要一个公开的隐私政策网页。

敲定的实现流程:

  1. 使用 AsciiDoc 编写隐私文件(纯粹是用习惯了)
  2. 使用 Asciidoctor 转换为 HTML
  3. 部署至 Cloudflare Pages(比 GitHub Pages 访问连通性更好)

最初是纯手动操作:项目中创建编辑 .adoc → 运行 asciidoctor 转 HTML → 手动上传至 Cloudflare Dashboard。.adoc 文件就放在代码项目中,一起维护。

随着接入的三方组件变多,隐私政策变动也更频繁,手动流程越来越繁琐。期望的效果是:推送 .adoc 变更后,自动转换 HTML 并部署至 Cloudflare Pages,同时支持手动触发。

注意:此处设计并未将隐私文件单独作为一个仓库,那样不方便。并且这也导致不能使用 Cloudflare Pages 直接读取 Github 自动部署方案。所以诞生了本文。

设计

目录架构

graph TB
    subgraph "assets/privacy_policy/"
        A["📁 privacy_policy"]
        
        subgraph "源文件 (Source)"
            B["📄 index.adoc<br/>中文隐私政策"]
            C["📄 en.adoc<br/>英文隐私政策"]
        end
        
        subgraph "templates/"
            D["📄 lang-selector.adoc<br/>语言切换选择器"]
        end
        
        subgraph "build/ (输出)"
            E["📄 index.html"]
            F["📄 en.html"]
        end
        
        A --> B
        A --> C
        A --> D
        A --> E
        A --> F
        
        B -.->|include| D
        C -.->|include| D
        B -.->|asciidoctor| E
        C -.->|asciidoctor| F
    end
    
    style A fill:#e1f5fe
    style B fill:#fff3e0
    style C fill:#fff3e0
    style D fill:#f3e5f5
    style E fill:#e8f5e9
    style F fill:#e8f5e9

说明:

目录/文件作用
*.adoc源文件,AsciiDoc 格式编写
templates/lang-selector.adoc共享的语言切换组件,被两个源文件 include
build/(非必须)构建输出目录,回写生成的 HTML

整体流程

flowchart TD
    subgraph Trigger["触发条件"]
        T1["push to main<br/>*.adoc 或 templates/** 变更"]
        T2["手动触发<br/>workflow_dispatch"]
    end
    
    subgraph Job["Github Actions: build-and-deploy"]
        direction TB
        S1["1️⃣ Checkout<br/>拉取代码"]
        S2["2️⃣ Setup Ruby 3.2"]
        S3["3️⃣ Install asciidoctor<br/>gem install asciidoctor"]
        S4["4️⃣ Build HTML<br/>asciidoctor .adoc → .html"]
        S5["5️⃣ Commit<br/>提交 build/*.html"]
        S6["6️⃣ Deploy<br/>部署到 Cloudflare Pages"]
        
        S1 --> S2 --> S3 --> S4 --> S5 --> S6
    end
    
    subgraph Cloudflare["Cloudflare Pages"]
        CF["wedrinkfun-privacy-policy"]
    end
    
    T1 --> Job
    T2 --> Job
    S6 --> Cloudflare
    
    style Trigger fill:#fff3e0
    style Job fill:#e3f2fd
    style Cloudflare fill:#fce4ec

流程说明:

步骤Action说明
1actions/checkout@v6检出代码
2ruby/setup-ruby@v1安装 Ruby 运行时
3gem install asciidoctor安装 AsciiDoc 转换工具
4内联脚本遍历 .adoc 文件,输出到 build/
5stefanzweifel/git-auto-commit-action@v7自动提交构建产物(带 [skip ci])
6cloudflare/wrangler-action@v3.15.0部署到 Cloudflare Pages

实现

整体思路:通过 GitHub Actions 串通流程,实现 push 即部署。

注意:这里实现了仅根据特定目录下的隐私文件更新推送,才会进行自动构建部署。

0. 准备隐私政策 adoc 文件

相信你应该有文件了吧,不然也不会看到这里。但是应该会考虑加上多语言版本,那么页面就需要一个语言切换按钮对不对。
这样的话就想到一起了。

提供下我的方案:adoc 中使用 include 引入 Passthrough Block。

这样可以避免依赖 JavaScript 动态生成 UI ,直接通过 AsciiDoc 的 include 宏嵌进去 HTML ,也就是你的多语言切换按钮设计代码。

index.adoc

= 微醺坊 (We Drink Fun) 隐私政策

include::./templates/lang-selector.adoc[]

**生效日期:2024年5月21日**

......

lang-selector.adoc

++++
<style>
  .lang-switcher-fixed {
    position: fixed;      /* 固定定位 */
    top: 20px;            /* 距离屏幕顶部 20px */
    right: 20px;          /* 距离屏幕右侧 20px */
    z-index: 9999;        /* 确保在最顶层,不被内容遮挡 */
    background-color: rgba(255, 255, 255, 0.9); /* 轻微透明的白色背景 */
    padding: 6px 12px;
    border-radius: 20px;  /* 圆角 */
    box-shadow: 0 2px 8px rgba(0,0,0,0.15); /* 增加一点阴影使其更精致 */
    font-size: 14px;
    font-family: sans-serif;
  }
  .lang-switcher-fixed a {
    text-decoration: none;
    color: #333;
    padding: 0 4px;
  }
  .lang-switcher-fixed a:hover {
    color: #0052cc;
  }
  .lang-switcher-fixed .divider {
    color: #ccc;
    margin: 0 4px;
  }
</style>

<div class="lang-switcher-fixed">
  <!-- 该路径在 web 服务器上可以生效,本地还是得用绝对完整路径。这么写是因为避免语法检查 -->
  <a href="./en">English</a>
  <span class="divider">|</span>
  <a href="./">简体中文</a>
</div>
++++

1. 获取 Cloudflare 信息

1.1 创建 API Token

Cloudflare Dashboard → My Profile → API Tokens → Create Token,搜索 Cloudflare Pages,选择模板即可。

1.2 获取 Account ID

两种方式:

  1. 最简单粗暴的方法: 登录 Cloudflare 后,浏览器地址栏 dash.cloudflare.com/ 后面那串就是 Account ID
  2. 最直观的的方法: 打开「Workers 和 Pages」,页面右下角可见

Account ID 位置

2. 配置 GitHub Secrets

打开仓库 → Settings → Secrets and variables → Actions,填入上一步获取的信息:

Secret 名称说明
CLOUDFLARE_API_TOKEN第 1 步创建的 API Token
CLOUDFLARE_ACCOUNT_ID第 1 步获取的 Account ID

GitHub Secrets 配置

3. 创建构建脚本

本来写了非常复杂的脚本完成一些工作,想了想看着难受。
把能删的都删了,不能删的迁移至工作流yml实现了,主打一个优雅。

3. 创建 GitHub Actions Workflow

注意:

  1. 工作流配置了 paths 过滤,只有 assets/privacy_policy/ 目录变更时才触发,不影响其他代码的 push。
  2. 实现了将构建后的 HTML 文件提交回仓库。

新建文件 .github/workflows/deploy-privacy.yml:

# 隐私政策自动部署工作流
# 当 assets/privacy_policy/ 目录下的 .adoc 文件有变更时,自动构建 HTML 并部署到 Cloudflare Pages

name: Deploy Privacy Policy

# 触发条件
on:
  push:
    branches: [main]
    paths:
      - 'assets/privacy_policy/*.adoc'        # 隐私政策内容变更
      - 'assets/privacy_policy/templates/**'  # 模板变更
  workflow_dispatch:  # 支持手动触发

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write  # 需要写权限以提交构建后的 HTML 文件
    steps:
      # 拉取代码
      - uses: actions/checkout@v6

      # 安装 Ruby(asciidoctor 依赖)
      - name: Set up Ruby
        uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.2'

      # 安装 asciidoctor(AsciiDoc 转 HTML 工具)
      - name: Install Asciidoctor
        run: gem install asciidoctor

      # 构建 HTML:将 .adoc 转为 .html
      - name: Build privacy policy HTML
        run: |
          mkdir -p assets/privacy_policy/build
          for adoc in assets/privacy_policy/*.adoc; do
            filename=$(basename "$adoc")
            html_name="${filename%.adoc}.html"
            echo "Building $filename → $html_name..."
            asciidoctor "$adoc" -o "assets/privacy_policy/build/$html_name"
          done

      # 将构建后的 HTML 文件提交回仓库
      # 使用 [skip ci] 避免触发无限循环(提交的文件在 paths 过滤范围内)
      - name: Commit HTML files
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: "build: update privacy policy HTML [skip ci]"
          file_pattern: 'assets/privacy_policy/build/*.html'

      # 部署到 Cloudflare Pages
      - name: Deploy to Cloudflare Pages
        uses: cloudflare/wrangler-action@v3.15.0
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: pages deploy assets/privacy_policy/build --project-name=wedrinkfun-privacy-policy

4. 效果

推送变更后,GitHub Actions 自动触发构建和部署:

GitHub Actions 执行成功

隐私政策页面已上线,中英文切换按钮正常显示:

隐私政策页面效果

最终样式:

https://wedrinkfun-privacy-policy.pages.dev/