返回博客列表

用 GitHub Issue + Next.js App Router 构建可持续的静态博客 / 专栏系统

2026-01-27
3 min read

> 在内容型项目中,我们经常会遇到几个现实问题: 不想维护数据库 不想自建 CMS 希望内容版本可追溯 希望写作流程尽量贴近开发习惯 同时又想要 SSG 的性能 + SEO 基于这些目标,我最终采用了一套工程化、低维护、可长期运行的方案: > GitHub Issue 作为内容源 > Next.js App Router 在 build 阶段生成静态站点 > GitHub Webhook...

在内容型项目中,我们经常会遇到几个现实问题:

  • 不想维护数据库
  • 不想自建 CMS
  • 希望内容版本可追溯
  • 希望写作流程尽量贴近开发习惯
  • 同时又想要 SSG 的性能 + SEO

基于这些目标,我最终采用了一套工程化、低维护、可长期运行的方案:

GitHub Issue 作为内容源 Next.js App Router 在 build 阶段生成静态站点 GitHub Webhook 触发自动重新构建

这篇文章完整总结这套方案的设计思路与实现要点。


一、整体架构概览

先给出最终架构图(逻辑):

GitHub Issue(文章 / 专栏)
        ↓
GitHub GraphQL API
        ↓(build 阶段)
Next.js App Router(SSG)
        ↓
Vercel 静态部署

核心原则只有一句话:

👉 所有内容只在 next build 阶段获取 👉 线上访问永远不请求 GitHub


二、为什么选择 GitHub Issue 作为内容源

1️⃣ 天然的 Markdown 支持

  • Issue Body = Markdown
  • 支持代码块、表格、图片、任务列表
  • 和开发者写 README 的体验完全一致

2️⃣ 版本控制 & 历史可追溯

  • 每一次修改都有记录
  • 可以对文章内容回滚
  • PR / Review / Comment 天然支持

3️⃣ 白嫖一个 CMS 后台

GitHub 自带:

  • 编辑器
  • 标签系统(Labels)
  • 里程碑(Milestone)
  • 搜索
  • 权限管理

👉 不用写一行后台代码


三、内容模型设计(重点)

1️⃣ 基本映射关系

GitHub博客系统
Issue文章
Milestone专栏(Series)
Label分类 / 状态
Comment Count评论数

2️⃣ 推荐约定(非常重要)

Issue 约定

  • Title:文章标题

  • Body:文章正文

  • Labels:

    • post(表示可发布)
    • draft / published
  • Milestone(可选):所属专栏

Milestone 约定

  • Title:专栏名称
  • Description:专栏简介
  • Due date:专栏完结时间(可选)

四、为什么用 Next.js App Router + SSG

1️⃣ 目标很明确

  • 页面是 内容型
  • 更新频率低
  • SEO 很重要
  • 首屏速度优先

👉 SSG 是最合适的选择


2️⃣ App Router 的优势

  • 原生支持 async Server Component
  • 原生支持 generateStaticParams
  • fetch 缓存语义清晰
  • 不再需要 getStaticProps / getStaticPaths
ts
export const dynamic = "force-static"
export const dynamicParams = false

这两行,明确告诉 Next.js:

构建时生成所有页面,运行时不兜底


五、构建时拉取 GitHub 数据

1️⃣ 使用 GitHub GraphQL API

相比 REST API:

  • 请求更少
  • 字段可控
  • 有 cost 概念,更适合 build-time

典型查询结构:

graphql
query GetPosts {
  repository {
    issues {
      nodes {
        title
        body
        milestone { title }
        labels { nodes { name } }
      }
    }
  }
}

2️⃣ 必须注意的一个坑:fetch 缓存

在 App Router 中:

ts
fetch(url, {
  cache: "force-cache"
})
  • build 阶段会缓存结果
  • 如果你在构建过程中多次请求同一 query
  • 很容易出现「数据不更新」

👉 解决方案:

  • build 阶段允许缓存
  • webhook 触发时重新 build
  • 不在 runtime fetch GitHub

六、专栏(Series)是怎么做的

核心思想

Milestone = 专栏

这是 GitHub 官方设计就支持的用法。

专栏能力直接白嫖:

  • 专栏名称
  • 专栏简介
  • 文章数量
  • 完成进度(progressPercentage)

前端可以轻松做出:

  • 专栏列表页
  • 专栏详情页
  • 阅读进度条

七、自动更新:GitHub Webhook + Vercel

工作流:

  1. 新建 / 编辑 Issue
  2. GitHub 触发 Webhook
  3. 调用 Vercel Deploy Hook
  4. 自动 next build
  5. 生成新的静态站点

👉 整个过程 无需手动干预


八、性能 & Rate Limit 分析

GitHub GraphQL API:

  • 每小时 5000 点
  • 普通 Issue 查询 cost ≈ 1

实际情况:

  • 一次 build 用几十点
  • 每天 build 十几次都没压力

而线上访问:

  • 0 GitHub 请求
  • 完全静态资源
返回博客列表
最后更新于 2026-01-27
想法或问题?在 GitHub Issue 下方参与讨论
去评论