博客的构建流水线是怎么跑的

文章写完之后, 总不能手动一条条部署. 自动化的目的很简单: push 完代码就什么都不用管了.

本质上就两件事: 把 Markdown 变成静态文件扔到网上去, 顺便把构建流程自动化.

Gulp 任务

整个构建就两个 Gulp 任务, 串行跑:

gulp.task("default", gulp.series('build', 'generate-service-worker'));

build

gulp.task('build', () => gulp.src('./').pipe(shell(['hugo --buildFuture --minify'])));

一行代码. 调用 Hugo 构建, --buildFuture 允许发布未来日期的内容, --minify 在构建时做 HTML/CSS/JS 压缩.

为什么用 gulp-shell 而不是直接调用 Hugo? 因为后续需要在构建完成后做一些处理, Gulp 作为编排工具把任务串起来比较方便. 如果用 npm script 串命令也可以, 但 Gulp 的 task 定义更清晰, 错误处理也更直接.

generate-service-worker

gulp.task('generate-service-worker', () => {
    return workbox.generateSW({
        globDirectory: './public',
        globPatterns: ['**/*.{woff2,woff,js,css,png.jpg}'],
        globIgnores: ['sw.js'],
        swDest: `./public/sw.js`,
        clientsClaim: true,
        skipWaiting: true,
        runtimeCaching: [
            { urlPattern: /.*\.js/,    handler: 'NetworkFirst' },
            { urlPattern: /.*\.css/,   handler: 'StaleWhileRevalidate' },
            { urlPattern: /.*\.(?:png|jpg|jpeg|svg|gif)/,
              handler: 'CacheFirst',
              options: { cacheName: 'images', expiration: { maxEntries: 50 } } },
            { urlPattern: /.*\.html/,  handler: 'NetworkFirst' }
        ]
    })
    .then(() => console.info('Service Worker 生成完成'))
    .catch(error => console.warn('Service Worker 生成失败: ' + error));
});

这个任务用 Workbox 自动生成 SW, 具体原理和缓存策略在 PWA 与 Service Worker 那篇里讲了.

CI/CD

用 GitHub Actions 自动构建部署. 配置文件 .github/workflows/deploy.yml:

name: Deploy to Cloudflare Pages

on:
  push:
    branches: [master]
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: peaceiris/actions-hugo@v3
        with:
          hugo-version: "0.164.0"
          extended: true

      - uses: actions/setup-node@v4
        with:
          node-version: 24
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Patch theme for Hugo compatibility
        run: bash scripts/patch-theme.sh

      - name: Build
        run: npm run build

      - name: Deploy to Cloudflare Pages
        run: npx wrangler pages deploy public --project-name=time-friend
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

触发条件: push 到 master 或手动触发.

流程:

  1. checkout 代码
  2. 装 Hugo extended 版本 (需要 extended 来处理 SCSS)
  3. 装 Node 24 并缓存 node_modules
  4. npm ci 安装依赖 (比 npm install 快, 但要求 lock 文件必须存在且跟 package.json 一致. 如果本地忘了 commit lock 文件, CI 会直接挂掉. 遇到过.)
  5. 执行 theme patch 脚本 (修复旧主题在新 Hugo 下的兼容问题)
  6. npm run build 触发 Gulp 构建
  7. 用 wrangler 部署到 Cloudflare Pages

CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID 存在 GitHub Secrets 里, 不在代码中暴露.

性能考虑

整个构建过程从 push 到部署上线, 大概两分钟. 其中构建本身十秒以内, 主要时间花在依赖安装和部署上.

Service Worker 的缓存策略直接影响了页面加载性能. 首屏加载依赖 NetworkFirst 策略的资源需要等待网络, 但由于静态站点的 HTML 体积很小 (通常 5-10KB), 网络请求开销不大. 后续页面导航时, 大部分资源已经在缓存中, 体验接近原生应用.

workbox.generateSW 生成的 SW 文件大约 5KB, 对整体加载体积的影响可以忽略.

文章链接:

/zh/archive/blog-architecture-build-pipeline-pwa/

# 相关文章推荐