AI 技术博客
教程6 分钟阅读3227

一个下午,从零到公网上线一个 AI 技术博客

完整记录这个博客的搭建过程:12 个阶段、从 PRD 到公网可访问、再到用独立 agent 自动化运维。全程由 Claude Code 驱动,踩过的坑都在这里。

这个博客本身就是一次实验:能不能在一个下午内,从零到公网上线,再配一个 agent 代管内容?

答案是可以。这篇文章是完整流水账。

路线图:12 个阶段

阶段 0-1   仓库脚手架 + 设计令牌
阶段 2-3   MDX 内容管线 + 首页/列表/详情
阶段 4-5   标签/分类/归档 + AI 工具目录
阶段 6-7   搜索/RSS/SEO + Giscus 评论
阶段 8     飞书机器人对接
阶段 9     互联网访问 (Vercel 试水)
阶段 10    切到 Cloudflare Pages (静态)
阶段 11    独立 blog-agent 运维
阶段 12    写这篇文章

每个阶段对应一个 git commit,可以 git log --oneline 看到时间线。

技术选型

不吹某个框架,只解释为什么:

选型原因
框架Next.js 15 App RouterSSG 性能好,MDX 社区成熟,有 output: 'export' 可静态化
样式Tailwind + OKLCH tokens8px 基线网格,深浅色自动切换,字号阶梯 ≤ 6 档
内容Markdown + git无数据库,版本即历史,写作用任何编辑器
搜索Pagefind构建时索引,零后端成本,浏览器直接查
评论GiscusGitHub Discussions 托管,零服务器,天然反滥用
托管Cloudflare Pages免费,无 SSO 保护,国内访问快
运维独立 blog-agent不污染博客仓库

关键设计约束

四条硬约束写在 PRD 里,所有代码必须服从:

  • 简约:首页主要板块 ≤ 3 个,图标仅一套,主色 ≤ 2 种
  • 简洁:字号 ≤ 6 档,圆角 ≤ 3 种,阴影 ≤ 2 级
  • 工整:8px 基线网格,文章 720px / 目录 1200px 最大宽度
  • 排版合理:正文 16-18px,行高 1.7,段宽 60-75 字符

这些不是口号,是可验收的规则。Tailwind config 里字号只写了 6 档,想加第 7 档会被评审打回。

静态 vs 动态:一个开关

next.config.mjs 里加了 BUILD_MODE 开关:

const STATIC = process.env.BUILD_MODE !== 'dynamic';

const nextConfig = {
  ...(STATIC && { output: 'export' }),
  trailingSlash: STATIC,
  images: {
    ...(STATIC && { unoptimized: true }),
  },
};

现在默认静态,部 Cloudflare Pages。未来要加用户登录/收藏:

export BUILD_MODE=dynamic && npm run build
# 改部 Vercel 或自建

代码主体一行不用动。

几个真实踩过的坑

1. YAML 的 date 字段会被解析成 Date 对象

gray-matter 把 frontmatter 里的 date: 2026-04-29 自动解析成 JavaScript Date,但我在 TypeScript 里声明的是 string。构建时报:

TypeError: r.date.slice is not a function

修:在解析层强制转字符串:

function toISODate(value: unknown): string | undefined {
  if (value == null) return undefined;
  if (value instanceof Date) return value.toISOString().slice(0, 10);
  if (typeof value === 'string') return value.slice(0, 10);
  return String(value);
}

2. Vercel 免费版默认给所有 .vercel.app 域名加了 SSO 保护

第一次部署成功后,任何人访问都会被重定向到 Vercel 登录页。ssoProtection: { deploymentType: 'all_except_custom_domains' } 是团队级默认。改项目 null 后需要重新部署,因为保护策略在部署时快照。

为了少折腾,直接切 Cloudflare Pages。Pages 免费版没有这个保护。

3. Next.js 15.1.3 被 Vercel 拒绝部署

Vulnerable version of Next.js detected。升到 16.2.4,顺手把 eslint-config-next 也升了,测试仍全绿。

4. RSS/Sitemap route 在 output: 'export' 下需要显式 force-static

export const dynamic = 'force-static';

export default function sitemap() { ... }

不加会报 not configured on route with output: export

blog-agent:独立的运维层

博客主站只管展示,所有自动化放在独立仓库 ~/blog-agent:

能力一览:
  写:write / write-tool / revise     (走 LLM)
  发:publish / deploy                (git + wrangler)
  运维:status / drafts / stale-tools / health

两个仓库关系:

~/ai-blog        博客主站(不认识 agent)
~/blog-agent     工具(通过 BLOG_ROOT 读写博客仓库)

这样分离的好处:

  • 博客仓库保持干净,未来换前端框架不影响 agent
  • agent 演进不用动博客代码
  • CI/CD 可以独立配置

举例,发一篇新文章的完整流程:

cd ~/blog-agent
node bin/agent.mjs write "一个清晰的主题"     # AI 生成草稿
# 编辑器审阅 ~/ai-blog/content/posts/xxx.mdx
node bin/agent.mjs publish xxx                # draft:false + commit + push
node bin/agent.mjs deploy                     # build + Cloudflare 部署
node bin/agent.mjs health                     # 线上 URL 探测

每一步都幂等,跑第二次无副作用。

性能指标

构建产物:

  • 28 个页面全部 SSG
  • 首页 First Load JS ~110KB
  • 全部 HTML + 静态资源 3.2MB
  • Lighthouse 目标 ≥ 98

线上实测(Cloudflare Pages,北京网络):

200 /           1060ms
200 /posts/      592ms
200 /tools/      197ms
200 /rss.xml     198ms
200 /sitemap.xml 277ms

首屏渲染的大头在于 Cloudflare 边缘节点首次建连,二次访问基本 < 300ms。

总成本

  • 域名:未买,用 *.pages.dev 免费子域
  • 托管:Cloudflare Pages 免费
  • LLM:MiLLM 内部网关,团队内部免费
  • 评论:Giscus 免费
  • 搜索:Pagefind 构建时生成,无后端
  • 总计:¥0

下一步

  • 补 10 篇种子教程
  • 工具目录扩到 30 条以上
  • 买自定义域名,绑到 Pages
  • GitHub Actions 自动部署(目前还是本地 wrangler)
  • 尝试把 agent 接到飞书机器人,让"@机器人 发一篇关于 X 的文章"直接走完全流程

延伸阅读

  • docs/PRD.md:v1.2 产品需求文档,四条硬约束和全部功能清单
  • docs/ARCHITECTURE.md:分层架构 + 路由映射
  • docs/DEPLOY.md:部署全流程
  • docs/FEISHU.md:飞书机器人双向接入指南

源码在 GitHub:https://github.com/a554524/ai-blog

评论

评论功能需要配置 Giscus 环境变量后启用。