之前每次改完博客,我都要:本地构建 → 把 dist 目录打成 zip → 打开 Cloudflare 控制台 → 进 Pages 项目 → Create deployment → 上传。改一个错别字也要走一遍,实在有点累。
现在换成了 GitHub + GitHub Actions 自动发布:改完代码推到 GitHub,大约一分钟后网站就自己更新了。你现在看到的这篇文章,就是我推送到 main 分支后自动发布上来的。
整体流程
我改代码 → git push 到 main ↓GitHub Actions 在 GitHub 的服务器上: 安装依赖 → 构建博客 → 用 wrangler 上传到 Cloudflare Pages ↓blog.dogelover.online(以及 dreamer-home.pages.dev)更新整个过程中,Cloudflare 那边什么都不用点,自定义域名 blog.dogelover.online 和原来的 dreamer-home.pages.dev 都会一起更新。
第一步:把源码放进 GitHub 私有仓库
我在 GitHub 上建了一个私有仓库 dreamer-home,把博客源码推了上去。私有的意思是只有我自己能看到源码,网站本身还是公开的。
推之前我特意检查了一遍,仓库里不能有任何密码或密钥。node_modules、dist 这类可以重新生成的目录也通过 .gitignore 排除掉了。
小插曲:用设备码登录 GitHub CLI
我是在一台远程的 Linux 电脑上操作的,那里没法方便地打开浏览器登录。后来发现 GitHub 官方命令行工具 gh 支持设备码登录:
gh auth login --web它会显示一个 8 位码,我在手机上打开 github.com/login/device,输入这个码、点一下授权,那台电脑就登录好了。全程不用在电脑上输密码,很适合这种场景。
第二步:写 GitHub Actions 工作流
GitHub Actions 就是 GitHub 提供的“自动化流水线”。在仓库里放一个 .github/workflows/deploy.yml 文件,告诉它“什么时候做、做什么”。这是我实际在用的文件:
name: Deploy to Cloudflare Pages
on: push: branches: [main] # 推送到 main 时自动运行 workflow_dispatch: # 也可以在 Actions 页面手动点一下运行
concurrency: # 连续推送时,取消还没跑完的旧任务 group: deploy-pages-${{ github.ref }} cancel-in-progress: true
permissions: contents: read # 只需要读代码
jobs: deploy: runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout uses: actions/checkout@v4
- name: Setup pnpm uses: pnpm/action-setup@v4 with: version: 9.14.4 run_install: false
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm
- name: Install dependencies run: pnpm install --frozen-lockfile
# 偶尔出现一次性的 Tailwind 报错,失败时自动重试,最多 3 次 - name: Build run: | for i in 1 2 3; do if pnpm build; then exit 0; fi echo "::warning::Build attempt $i failed, retrying..." sleep 5 done exit 1
- name: Deploy to Cloudflare Pages uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} wranglerVersion: "4" command: pages deploy dist --project-name=dreamer-home --branch=main --commit-dirty=true几个值得说的地方:
on.push.branches: [main]:只有推到main才发布。以后想先试验,可以在别的分支上改。pnpm install --frozen-lockfile:严格按pnpm-lock.yaml安装,保证 GitHub 上装的依赖版本和我本地一模一样。- 最后一步
wrangler-action:Cloudflare 官方提供的 Action,本质就是在 GitHub 的服务器上执行wrangler pages deploy dist,把构建好的dist目录上传到我已有的 Pages 项目dreamer-home。效果和我之前手动上传 zip 一样,只是不用我动手了。
为什么要“构建重试”
在本地构建时,我遇到过好几次:第一次 pnpm build 报一个 Tailwind 相关的错误,什么都不改再跑一次就好了。这种“偶发失败”(flaky)如果放到自动发布里,就会出现“明明代码没问题,发布却失败了”的情况。
所以我在 Build 这一步写了个小循环:失败了等 5 秒重试,最多 3 次,3 次都失败才真正算失败。这不是从根本上解决问题,但很实用。
第三步:最小权限的 API Token
GitHub 要往我的 Cloudflare 账号上传网站,就得有一把“钥匙”,也就是 Cloudflare API Token。
这里我学到的最重要的一点是:给钥匙的时候,只给刚好够用的权限。在 Cloudflare 控制台创建 Token 时,我没有用“全局 API Key”(那个能管整个账号),而是自定义了一个 Token,只勾了一项权限:
Account → Cloudflare Pages → Edit
这样就算这个 Token 哪天不小心泄露了,别人最多也只能发布 Pages,动不了我的 Workers、KV、DNS 或者账单。
存成仓库 Secrets
Token 和账号 ID 绝对不能直接写进 deploy.yml,否则就跟着代码一起进了仓库。正确做法是存到仓库的 Settings → Secrets and variables → Actions 里:
CLOUDFLARE_API_TOKEN:上面那个 TokenCLOUDFLARE_ACCOUNT_ID:Cloudflare 账号 ID
工作流里用 ${{ secrets.XXX }} 引用它们。Secrets 存进去之后连我自己都看不到原值,在运行日志里也会被自动打码成 ***。
第四步:验证
一切配好后,我先在 Actions 页面手动点了一次 Run workflow。大约一分钟,四个步骤全部打勾,刷新博客就看到了变化:侧边栏的 GitHub 按钮现在指向我的 GitHub 主页了。
然后就是这篇文章:我在本地写好 Markdown,git push 到 main,剩下的全交给 GitHub Actions。如果你能读到这里,说明它成功了 🎉
小结
| 之前(手动上传) | 现在(自动发布) | |
|---|---|---|
| 发布步骤 | 构建、打包、登录控制台、上传 | git push |
| 改一个错别字 | 好几分钟 | 推完等一分钟 |
| 历史记录 | 没有 | 每次改动都在 Git 里 |
| 出错排查 | 靠记忆 | 看 Actions 日志 |
这次学到的关键词:私有仓库、GitHub Actions 工作流、wrangler-action、最小权限 Token、仓库 Secrets、构建重试,还有 GitHub CLI 的设备码登录。
下一步打算试试 Cloudflare 的 D1 数据库,给博客加个留言板或访问计数。