从 Hugo 到 Astro:用 Codex 与 GPT-6 Astra 完成博客迁移和主题拆分
AI 参与说明(Agent:Codex):本文根据本次博客迁移的需求、代码提交、构建记录和官方资料整理,属于 AI 辅助生成内容。本任务可核验的运行参数为模型
gpt-6-astra、reasoning effortultra、执行入口 Codex Desktop、提供方 OpenAI;运行记录中的 Codex CLI 版本为0.153.4,不代表桌面 App 版本。下文的项目结果来自实际验收,模型能力说明引用官方资料,二者不互相替代。
CI/CD 修订说明(2026-09-08,Agent:Codex):本次核对三个仓库的职责、现有工作流、构建与部署脚本,更新自动发布流程、配置步骤和验收边界。执行入口为 Codex Desktop;本次完整模型标识与 reasoning effort 未取得可核验的运行记录,不能沿用初稿的参数。
这次迁移把 yindongliang.com 从 Hugo + Hugo Book 切换到了 Astro,并拆出独立的 astro-book 主题。博客运行在 Cloudflare Workers Static Assets 上,主题自己的英文文档演示运行在 tcitry.github.io/astro-book。
读者熟悉的导航、三栏布局、文章地址、分类标签和评论继续保留;工程侧则可以在同一站点中使用 React、HeroUI、HeroUI Pro 和其他前端组件。本文的迁移叙述记录 2026-09-07 的实施过程;CI/CD 章节更新至 2026-09-08 的脚本与已记录验收状态,说明迁移后怎样持续发布内容、站点代码和主题升级。
| 英文术语 | 中文名称 | 简要解释 |
|---|---|---|
| Astro | Astro 站点框架 | 将文章与组件构建为页面,交互区域按需加载客户端代码 |
| Static Assets | 静态资源 | 构建产生的 HTML、样式、脚本和附件,由 Cloudflare 提供访问 |
| CI/CD | 持续集成与持续交付/部署 | 把检查、构建和发布串成可重复的流程;本站生产流水线包含自动部署 |
| Workers Builds | Workers 云端构建 | Cloudflare 在云端检出站点代码,执行配置的构建和部署命令 |
选型:让内容站能够持续承载前端实验
迁移的出发点是一个具体的工程矛盾:Hugo 已经很好地承担静态内容发布,但新的交互实验往往另起一个前端工程,随后再处理构建、资源复制和嵌入。内容页面与 demo 的实现逐渐分散,组件难以在文章和独立演示页之间复用。
同时,已有 Hugo Book 的外观已经经过反复调试。换框架的前提是维持阅读体验,增加前端扩展能力。最终约束包括:
- 保留现有布局、URL、分类标签、Giscus、LaTeX、Mermaid 和代码展示能力。
- React 是当前主要交互技术,但后续允许 Svelte、Vue、Three.js 等研究进入同一站点。
- Weekly、Timeline、Portfolio、Links 等页面继续高度定制。
- 迁移首轮优先静态生成,不引入独立业务后端;后续读者功能与搜索服务的发布步骤见 CI/CD 章节。
- 新界面优先使用 Tailwind CSS v4;不适合用 utilities 表达的局部规则再使用 CSS Modules。
这些条件使 Astro 成为本次方案。Astro 可以在页面层组合不同框架组件,并通过 client:* 指令控制交互代码的加载;没有客户端指令的框架组件默认可以生成静态 HTML。这适合以文章为主体、按需加入交互区域的结构。Astro 框架组件文档
| 候选方案 | 本项目中的取舍 |
|---|---|
| 裸 Vite + React | 适合独立实验;作为整站方案还要补齐内容模型、路由输出、元数据和发布流程 |
| Fumadocs + React Router | 曾作为主要候选;本项目更需要保留自有布局,并让多框架实验自然共存,因此没有采用 |
| Astro + Starlight | 可以复用成熟文档站能力;本项目最终自行维护 Book 风格主题,没有引入 Starlight 依赖 |
| Astro + astro-book | 保留可控的页面结构,将通用阅读能力沉淀为主题,业务页和交互实验独立演进 |
这是针对已有站点的选择,不能据此推导 Fumadocs 不适合 SEO,或 Starlight 无法定制。迁移旧内容、URL 和业务行为的工作,也不会因为换成任何一个框架自动消失。
从方案到上线,工作如何逐步展开
整个过程经历了多轮实现和 review,范围在实际检查中逐渐明确。
| 阶段 | 实际完成的工作 |
|---|---|
| 盘点与定方案 | 检查旧 Hugo 配置、主题覆盖、内容输入、URL 和评论规则,确定 Astro 静态方案 |
| 可运行与交互验证 | 建立 Book 布局、内容兼容层和 /lab/,验证 React、HeroUI、HeroUI Pro、Tailwind v4 与 Svelte |
| 拆分主题 | 创建独立 astro-book,将通用布局、正文能力和公开接口移入主题,业务页面保留在站点 |
| 对照旧站修正 | 恢复侧栏宽度、周刊尺寸、标签间距、归档锚点和滚动行为,删除额外添加的导航内容 |
| 预览验收与生产切换 | 在迁移预览环境检查,备份 Hugo 分支,Astro 转正,主域转到 Cloudflare |
| 简化发布结构 | 收敛为一个生产 Worker,移除迁移预览子域名和 Worker |
| 主题独立展示 | 用通用内容建立英文文档示例,部署到主题自己的 GitHub Pages 路径 |
| 搜索职责收敛 | 将 Pagefind 依赖、构建集成和搜索界面统一放进主题,分别部署主题示例和博客 |
| 开发约定整理 | 保留旧分支的开发规则,更新 Astro 入口,并将日常开发归回主检出的 main 分支 |
分阶段的价值在于,每一轮都有可以打开、比较和检查的结果。例如,能构建出页面后继续检查 URL;能显示 demo 后继续检查真实交互;主题能在博客中使用后,再检查离开博客环境是否仍能独立安装。
三个项目各自负责什么
最终结构保留内容与程序的分离,同时把通用主题从站点业务中拆出来。
flowchart TD
C["Blog 内容仓库<br/>Markdown、附件、内容历史"] -->|"受控只读导入"| S["博客站点工程<br/>内容适配、路由、业务页面"]
T["astro-book 公开主题<br/>布局、正文能力、搜索"] -->|"固定提交与打包产物"| S
I["站点内交互组件<br/>React、HeroUI Pro、Svelte"] --> S
S --> B["Astro 静态构建<br/>HTML、资源、本站搜索索引"]
B --> W["Cloudflare Workers Static Assets<br/>yindongliang.com"]
T --> E["独立英文文档示例<br/>仅使用主题内方案"]
E --> G["GitHub Pages<br/>tcitry.github.io/astro-book"]
Blog 保存内容。 站点构建通过 BLOG_DIR 读取允许发布的内容,再应用草稿和目录排除规则。框架迁移期间,不为了适应模板而批量修改正文、外链或引用。生成文件也不写回内容源。
astro-book 保存通用阅读能力。 包括布局、导航、TOC、文章列表与元数据组件、Markdown/MDX 支持、公式、图表、代码、搜索及可选评论展示。主题不依赖 React、HeroUI 或 HeroUI Pro,也不预设博客的栏目数据模型。
博客站点保存业务规则。 内容加载、URL、分类标签聚合、排序、RSS、sitemap、SEO 策略,以及 Weekly、Timeline、Portfolio、Links 和 Lab 都由站点维护。主题提供可复用组件和插槽,站点决定怎样组合它们。完整边界记录在主题的公开接口文档。
主题的样式使用 Tailwind v4,并将 utilities 预编译进包;必要的局部样式使用 CSS Modules。消费主题的项目不需要安装 Tailwind 编译器才能补齐主题样式。博客本身仍使用自己的 Tailwind v4 构建,开发业务界面。
截至本文记录时,astro-book 尚未发布 npm 正式包。博客固定主题的完整 Git 提交,先构建真实 tarball,再按 lockfile 安装。独立消费项目测试会从打包产物安装,避免主题在开发目录中可用,离开本机的源码和依赖环境就失效。
兼容工作:把“和以前一样”变成具体检查
内容路径和评论必须一起考虑
旧站使用过显式 URL、slug、分区 permalink、中文路径和目录索引。迁移不能简单地把文件路径交给新框架的默认路由规则。
实现中建立旧 URL 基线,并在内容适配层处理 front matter、_index.md、内部引用、导航和日期。分类值的类型需要归一化,修改时间需要保留内容 Git 历史的语义,避免检出时间影响排序与 sitemap。
Giscus 继续使用 pathname。它实际匹配的 term 去掉开头 /,但保留路径编码和结尾 /。因此,页面仍然能打开,不代表原有评论一定能匹配;大小写、编码和尾斜杠也属于兼容要求。
评论仍位于页脚前后篇导航之后,并且只对指定类型的独立内容页启用。目录、分类和标签索引不注入评论,避免目录前缀匹配到子文章讨论。主题负责展示插槽,站点负责页面适用条件;这次迁移没有通过新建讨论来替代已有评论。
布局和行为都要与旧站对照
最容易被忽略的部分,往往是已经调试过的尺寸和交互。
| 实际发现的问题 | 修正方向 |
|---|---|
| 左侧侧栏最大宽度与旧版不同 | 对照旧 Hugo 自定义值和响应式行为,保留阅读区域比例 |
| Weekly 卡片尺寸发生变化 | 恢复 320px 卡片、320 × 192px 封面与 16px 间距 |
Doc 与其他标签紧贴 | 补齐标签横向及换行间距,检查不同列表中的表现 |
| Archives 右侧分类跳到新页面 | 在博客层覆盖为当前页的 #id 滚动,主题继续提供通用分类行为 |
| 滚动条占位方式与旧站不同 | 对照根滚动容器和侧栏滚动规则,检查窄屏及宽屏 |
| 侧栏新增了未要求的“最近修改”列表 | 删除新增列表,保留站点原有的最近修改页面 |
| Lab 导航位置不符合预期 | 显示名称改为 Astro-book,放在顶部菜单 About 之后 |
这些修正说明,“功能没有丢失”还包括交互位置、页面内跳转、信息顺序和阅读密度。仅检查 HTTP 200 或 React 组件是否挂载,无法覆盖这些问题。
主题保留 Hugo Book 来源和许可证说明,后续可以选择性吸收上游功能;这并不是自动同步 Hugo Book 的实现。每次主题更新仍需同时验证独立示例和实际博客。
正文能力用真实旧文章验收
LaTeX 采用构建期 KaTeX 渲染,Mermaid 按需加载并保留源码回退,旧 Markdown 则通过兼容层处理历史写法。宽代码、宽表格和图表需要局部滚动,不能把整篇文章撑宽。
本轮还发现一处在旧 Hugo 中同样失败的 Mermaid sequence diagram。按照“先迁移架构、后集中修正文”的约定,该内容问题被记录并保留,没有借迁移静默改写文章。兼容验收应当区分迁移引入的问题和原文已有的问题。
React、HeroUI Pro 和多框架演示怎样进入博客
Astro-book 展示页承担了验证入口的角色:既展示主题能力,也展示博客自己的高级组件。它与主题的独立文档站不是同一个页面。
站点在原生 MDX 页面里组合 React 和 Svelte 组件。下面是当前 Lab 中使用的组合方式片段,前提是站点已配置对应的 Astro 集成,并存在两个组件文件:
import AgentReplay from '../../components/demos/AgentReplay';
import SvelteCounter from '../../components/demos/SvelteCounter.svelte';
<AgentReplay client:visible />
<SvelteCounter client:visible />
页面先生成可阅读的初始 HTML,组件进入视口时再加载交互。独立演示页复用同一份组件,需要立即交互时使用相应的加载指令。这符合 Astro 的客户端指令机制。多框架并存仍然会增加实际使用的运行时成本,不能视为免费能力。
HeroUI 展示覆盖输入、选择、开关、卡片、标签、Tabs、按钮和折叠面板。HeroUI Pro 用于代码块、消息、来源、步骤展示和消息操作。Agent 演示可以开始、暂停、调速、重置和查看完整结果,但内容来自本地预设数据,不调用在线模型,也不是已经交付的 AI 后端。
样式集成也做了针对性处理:避免完整全局 reset 改变文章排版,按实际组件导入样式,并将 Book 的明暗主题变量映射到 demo。选择器浮层可能挂载在组件容器之外,因此验收时必须真的打开浮层,检查颜色、裁切和键盘操作。
开发过程中也调整了 demo 范围:React 组件库最终只保留 HeroUI 和 HeroUI Pro,Kumo 相关演示及 cloudflare-product-map 被删除。rounded-timeline 则迁为 Astro 页面,继续保留原有访问地址,不再依赖单独的 Hugo 演示构建链。
需要明确一个尚未完成的边界:目前验证的是站点内原生 MDX,外部 Blog 内容直接导入 MDX 仍属于后续工作。既有文章继续使用 Markdown,没有整体改名为 MDX;Vue 和 Three.js 也属于后续研究方向,当前实际验证了 React 和 Svelte。
代码块优先复用现成组件,但保留静态正文
主题默认使用 Expressive Code 提供代码展示与复制。博客选择覆盖普通代码渲染,接入真实 HeroUI Pro CodeBlock,复用高亮、复制和反馈组件。这个覆盖留在站点中,公开主题没有因此依赖商业组件。
普通文章先输出完整的 pre/code 原文,包括空白、注释和实际末尾换行。代码接近视口时再加载共享的 React / Pro 模块,逐块挂载增强界面;脚本或组件失败时,原始代码仍可阅读和选中。Mermaid 源码展示继续复用主题能力,不能理解为博客完全删除了 Expressive Code。
长代码文章的检查确认了按需挂载生效,但第一次增强仍要加载 React、Pro、Motion 和 Shiki,高亮也会消耗浏览器资源。这里得到的是加载策略和功能验证结果,没有足够数据给出“性能提升了多少”的结论。博客 demo 与代码渲染说明
搜索:实现放进主题,索引属于各个站点
搜索经历了一次重要的职责收敛。
Astro 负责生成静态页面,Pagefind 负责根据这些页面生成搜索索引并在浏览器查询。采用 Astro 不会自动替代全文搜索引擎。Starlight 也将 Pagefind 作为默认站内搜索方案,本次参考了它把搜索集成到文档站构建和组件体系的方式,但没有引入 Starlight 本身。Starlight Site Search
最终由 astro-book 统一维护 Pagefind 依赖、Astro 构建结束后的索引步骤、搜索弹窗和资源路径。博客删除独立 Pagefind 依赖与重复命令,只配置自己的搜索范围和界面文案。
博客当前保留的配置片段是:
astroBook({
search: {
glob: '{docs,posts,weekly}/**/*.html',
rootSelector: 'main',
},
})
glob 匹配构建后的 HTML 路径,而不是源 Markdown。Links、Timeline 和根级页面不因这次整合自动进入索引。主题示例则搜索它自己的文档内容。
因此两个站点仍分别输出 pagefind/:博客有博客索引,主题文档站有文档索引。这是内容不同所需的两份数据,实现代码只维护一套。资源地址自动跟随 Astro 的 base,文档站部署到 /astro-book/ 后,搜索结果和资源也需要保留这个前缀。主题搜索接口
搜索应在完整 build 后通过 preview 验收。新启动的开发服务没有构建索引,不能只看到搜索框就认为搜索已经可用。主题也分别提供索引生成和页面搜索界面的开关,以便消费站明确控制两层行为。
本轮收敛对比了新旧 968 条搜索记录,URL、正文和元数据没有增删改;线上又分别检查英文与中文查询,以及点击后的实际落点。
CI/CD:三个仓库如何进入生产发布
2026-09-08 已有站点 main 推送触发 Workers Builds、云端构建及部署成功的记录。自动发布入口已经建立;Blog 内容通知的工作流也已实现,但本次修订尚未取得“一次内容 push 到线上正文更新”的完整验收记录,不能把它写成已验证完成。
迁移首次上线采用 Astro 静态输出与 Cloudflare Workers Static Assets,没有业务 Worker。后续代码增加了读者功能使用的 Clerk、Convex,以及同一个 Worker 中的搜索 API;文章主体仍静态构建,不因此改成 Astro 服务端渲染。下面的发布顺序按当前脚本说明,首次静态站部署成功的记录不能替代新增功能的生产验收。Cloudflare Static Assets
生产只保留 tcitry-blog 一个 Worker,使用默认 wrangler.jsonc。主域为 yindongliang.com,www 通过 Cloudflare Redirect Rule 保留路径与查询参数跳到主域。迁移预览 Worker 已移除,日常先本地检查。旧默认分支 master 与 Hugo 备份 hugo-book 保留,Astro 的生产入口是 main;package.json 是命令入口,不再保留 Hugo Makefile。
先分清三种更新入口
| 修改对象 | 发布动作 | 触发与结果 |
|---|---|---|
| Blog 内容 | 审查内容后 push 到内容仓库 main | GitHub Actions 通知站点,站点调用 Deploy Hook,请求一次云端构建 |
| tcitry-blog 站点代码 | 完成本地验收后 push 到站点 main | Cloudflare Git 集成直接触发 Workers Builds,构建成功后部署生产 |
| astro-book 主题 | 推送主题代码,再在站点升级固定主题提交和 lockfile | 主题自己的 CI 发布文档示例;博客要等站点升级提交进入发布流程 |
这里的 push 指推送到远端。只在本机 commit 不会触发云端构建;主题 CI 成功也不能证明博客已经部署。站点 main 是生产入口,不能把未经验证的 push 当作保存进度。
| 英文术语 | 中文名称 | 简要解释 |
|---|---|---|
| repository_dispatch | 仓库自定义事件 | 内容仓库向站点仓库发送事件,让站点的指定工作流运行 |
| Deploy Hook | 部署触发钩子 | 向专用 URL 发出 POST,请求 Cloudflare 构建指定分支 |
| Commit SHA | 提交标识 | 固定一次构建使用的代码或内容版本,避免构建中途跟随分支变化 |
| Release Manifest | 发布清单 | 记录发布来源、配置和资源哈希,用于验证实际上传的产物 |
| Check Run | 提交检查记录 | GitHub 中显示的检查状态;还需确认 Cloudflare 部署与线上结果 |
内容更新实际经过两段 GitHub Actions。Blog 的 Notify public site 发送 blog-content-updated 事件;站点的 Build updated Blog content 接收事件,再请求 Deploy Hook。事件不携带私有正文、内容仓库地址或 Commit SHA。
flowchart TD
B["Blog main push"] --> N["GitHub Actions<br/>Notify public site"]
N -->|"repository_dispatch"| R["GitHub Actions<br/>Build updated Blog content"]
R -->|"HTTP POST"| H["Deploy Hook<br/>main"]
H --> W["Workers Builds"]
S["tcitry-blog main push"] -->|"Git integration"| W
W --> C["Production build<br/>固定代码、内容与主题版本"]
C --> V["Verification<br/>检查并封存产物"]
V --> D["Production deployment<br/>发布并核验线上结果"]
A Deploy Hook requests a build for its configured branch. 它位于构建之前;GitHub Actions 发出请求后,由 Cloudflare 执行构建与部署。Hook 返回成功表示请求被接受,不表示生产站已更新。Deploy Hooks 官方文档
云端如何固定输入并完成构建
Workers Builds 先检出站点代码,然后执行 npm run build:workers。项目脚本读取 Blog 的 main 完整 Git 历史,将本次取得的远端分支解析为一个完整 Commit SHA,再以 detached checkout 固定该提交。保留历史是为了让修改日期沿用内容历史,而不是变成云端检出时间。
因此,日常不需要配置或反复修改 BLOG_CONTENT_COMMIT。构建期间即使 Blog 又有推送,当前构建仍使用已经固定的版本;新内容由后续构建处理。一次通知的语义是“重新构建最新可用内容”,不保证与发出通知的那一笔提交一一对应。
BLOG_CONTENT_COMMIT 仅用于回滚或复现时的可选覆盖:必须是内容 main 历史中的完整 40 位 SHA。恢复日常发布时删除该变量,不要保留旧值或设为空字符串,否则可能一直发布旧内容或直接校验失败。站点代码和主题也有各自的固定来源:前者来自本次站点检出,后者来自站点记录的主题提交与锁定依赖。
| 阶段 | 当前脚本执行的工作 |
|---|---|
| 环境检查与内容检出 | 校验生产配置和授权,固定 Blog 内容提交 |
setup | 先准备固定主题 tarball,再安装 lockfile 锁定的依赖及授权组件 |
build | 在生产环境生成 HTML、资源、Pagefind 索引和已启用的搜索语料 |
check、test | 执行 Astro、读者功能类型检查、公开仓库检查及项目测试 |
verify:release | 校验生产产物、来源及资源哈希,生成 Release Manifest;构建前后核对源码版本 |
| 清理 | 删除临时内容检出,保留已经验收的站点产物,供部署步骤使用 |
build:workers 内部的 build 继承 PUBLIC_SITE_ENV=production,任一步失败都会停止。Blog 读取凭据只交给 Git,HeroUI Pro 授权只交给 setup,部署凭据不传给依赖脚本和内容渲染器。具体实现见云端构建脚本。
构建成功后,部署同一份已验收产物
Cloudflare 的 Deploy command 是 npm run deploy:verified。它读取 Release Manifest,确认产物与配置没有变化,再调用 lockfile 对应的本地 CLI。这里不能重新 build,更不能让另一个任务改写正在上传的 dist/。
当前脚本还包含迁移后新增功能的部署阶段:
- 检查生产 Clerk、Convex 配置与发布清单一致;启用 AI Search 时,先检查远端权限与语料同步计划。
- 校验 Convex 的生产目标及 Clerk issuer,部署已经检查过的 Convex schema/functions。
- 重新核对产物,使用 Wrangler 上传 Worker 与 Static Assets,随后检查本地资源哈希仍一致。
- 发布清单包含 AI Search 时,核验线上发布标记、页面与搜索接口,再同步已发布文章语料。
这不是跨平台原子发布。Convex 成功而 Worker 失败时,旧前端可能继续访问新后端,所以 schema/API 变更必须兼容仍在线的版本。Worker 已发布后语料同步失败,也不能说“生产没有变化”;需要根据失败阶段核对线上版本,再修复和重试。完整实现见部署脚本。
Cloudflare 的一次性配置
在 Workers & Pages → tcitry-blog → Settings → Builds 核对以下配置。Git 连接使用站点仓库 tcitry/tcitry.github.io,Blog 内容仓库由构建脚本单独读取。
| 字段 | 配置 |
|---|---|
| Production branch | main |
| Root directory | / |
| Build command | npm run build:workers |
| Deploy command | npm run deploy:verified |
| Builds for non-production branches | 关闭 |
| API token | 为该生产 Worker 构建部署配置的 Cloudflare 授权 |
没有额外的 Wrangler production 环境,也不再使用 wrangler.production.jsonc。PUBLIC_SITE_ENV=production 控制产物的生产收录策略,不能替代以上 Git 分支和部署设置。
基础构建配置放在 Builds → Variables and secrets,不是仅配置 Worker 运行时变量:
| 名称 | 类型与用途 |
|---|---|
SKIP_DEPENDENCY_INSTALL | Variable,值为 1,由项目 setup 接管安装顺序 |
NODE_VERSION | Variable,值为 24;实际 Node/npm 版本以构建日志为准 |
PUBLIC_SITE_ENV | Variable,值为 production |
BLOG_CONTENT_REPOSITORY | Secret,私有内容仓库的 owner/repo,不包含完整 URL |
BLOG_READ_TOKEN | Secret,仅授予读取内容仓库所需的权限 |
HEROUI_AUTH_TOKEN | Secret,HeroUI Pro 的 CI/CD 安装授权 |
SKIP_DEPENDENCY_INSTALL=1 在本项目中需要保留。 平台默认安装发生得太早:lockfile 引用的主题 tarball 尚未生成,就可能找不到文件。项目先准备主题包,再执行安装;删除该变量既不符合当前脚本校验,也会破坏这个顺序。Workers Builds 构建镜像
随着读者功能和 AI Search 加入,当前发布脚本还要求相应配置,不能照搬首次静态站成功时的三项 Secret 就认为配置齐全:
| 名称或位置 | 当前用途 |
|---|---|
PUBLIC_CLERK_PUBLISHABLE_KEY、PUBLIC_CONVEX_URL | Builds 中的生产公开配置,在构建时进入前端;值不硬编码进仓库 |
CONVEX_DEPLOY_KEY | Builds Secret,生产后端部署使用;不传入前端产物 |
Convex production 中的 CLERK_JWT_ISSUER_DOMAIN | 与生产 Clerk 实例对应,部署时检查;不配置到错误的环境 |
CLOUDFLARE_ACCOUNT_ID、CLOUDFLARE_API_TOKEN | 启用 AI Search 的发布还需要供同步脚本读取,并具备对应权限;令牌作为 Secret 保存 |
以上仅列变量名和用途,不公开真实配置。Hook URL、私有内容地址、访问令牌与商业组件源码都不进入 Git;构建环境的 Secret 也不因使用 PUBLIC_* 名称就变得适合公开。读者功能的实例划分、搜索资源与授权细节随代码维护在站点持续部署文档。
Blog 内容通知的一次性接入
现有两个工作流分别承担“通知站点”和“请求 Cloudflare 构建”,无需每次内容更新都修改站点代码或配置 Commit SHA。一次性接入步骤如下:
- 在 Cloudflare 的
tcitry-blog→ Settings → Builds → Deploy Hooks 创建 Hook,名称可用blog-content-production,分支选择main,复制生成的 URL。 - 打开 站点仓库
tcitry/tcitry.github.io→ Settings → Secrets and variables → Actions → New repository secret。名称为CLOUDFLARE_DEPLOY_HOOK,值为完整 Hook URL。GitHub Actions Secret 配置 - 确认 Blog 内容仓库已有 Actions Secret
TCITRY_SITE_DISPATCH_TOKEN,能够向站点仓库发送repository_dispatch。它负责跨仓库通知,与读取内容的BLOG_READ_TOKEN用途不同。 - 在站点 Actions 手动运行
Build updated Blog content,先验证 Hook 请求;再通过一次已审查的 Blogmainpush 验证整条链路。首次验证完成后,日常只需正常推送内容。
Hook URL 本身是触发凭据,不写进工作流源码、文档或聊天。站点工作流从 Secret 读取它,校验目标地址,发送有超时限制的 POST 并检查响应成功;不会自动跟随重定向或盲目重试。实现见站点内容更新工作流。
短时间连续提交时,不能按 Hook 请求数推算部署次数。Cloudflare 可能合并仍处于 queued / initializing 阶段的 Hook 构建;站点 Actions 的并发组只串行化通知请求,不代表整条云端构建已经串行化。验收应关注最终生产内容是否包含所需更新。Deploy Hook 响应与去重行为
日常使用、缓存与手动恢复
日常改内容时,在 Blog 审查正文、链接和脱敏结果,再 push main。改站点代码时,先准备授权安装环境与本地配置,完成构建、类型检查、测试和实际页面验收,再 push 站点 main。下面是已完成 npm run setup 后的本地预览命令;端口选择本机空闲端口:
BLOG_DIR=/path/to/Blog npm run build
npm run check
npm test
npm run verify
npm run preview -- --port 4321
普通 build 默认产生 noindex 预览产物。手动生产恢复也必须从独立检出开始,使用固定内容快照、独立依赖、缓存和 dist/,经过生产构建与 verify:release 后再执行 deploy:verified;不得直接上传共享开发目录的预览产物。生产配置缺失或新增登录、权限链路尚未验收时,不推送站点 main 触发生产发布。
全量构建与增量上传是两件事。 当前流程仍生成完整 Astro 站点;Wrangler 按静态资源哈希复用服务端仍可用且未变化的文件,只上传服务端要求补齐的资源。自动流程的构建与上传都在 Cloudflare 构建环境中完成,本机不必保持运行。资源复用不等于按 Markdown 提交只重建部分页面。Static Assets 上传机制
Workers Builds 的依赖和框架缓存可以缩短重复构建,但不会替代版本固定、测试或 Release Manifest 校验。排查异常时可以清缓存复现,不应通过跳过检查来提速。Workers Builds 缓存
怎样判断发布完成,失败时从哪里查
| 观察位置 | 成功说明什么 | 失败或缺失时先检查什么 |
|---|---|---|
Blog Actions:Notify public site | 跨仓库事件已经发送 | dispatch token、目标仓库、工作流所在分支 |
站点 Actions:Build updated Blog content | Deploy Hook 请求被接受 | Hook Secret 是否存在、URL 是否有效、Cloudflare 响应 |
| Cloudflare Builds 的 Build 阶段 | 本次代码与内容通过云端构建、检查和产物校验 | 首个失败步骤;区分平台镜像初始化失败与项目脚本失败 |
| Cloudflare Builds 的 Deploy 阶段 | 配置的部署命令执行成功 | 发布清单、生产配置、Convex、Wrangler 或语料同步的具体失败阶段 |
| 生产版本与线上页面 | 需要的更新已经生效且可访问 | 正文、链接、搜索落点、资源、404 与新增读者功能的真实登录和数据隔离 |
GitHub 的 Check Run 可以提供云端构建详情入口,但内容通知成功、云端构建成功、部署成功和业务验收通过是不同层次。不能仅凭 GitHub Actions 的绿色状态就声称文章已上线,也不把它当作默认成功邮件或主动消息通知。Workers Builds GitHub 集成
当前 wrangler.jsonc 还启用了 observability,其中 enabled 为 true、head_sampling_rate 为 1。构建与部署失败先看 Builds 日志;请求进入 Worker 后的运行问题再结合 Observability 排查,二者服务于不同阶段。
截至本次修订,可确认 2026-09-08 已完成首轮站点 Git push 的云端构建、部署与线上页面检查;该历史记录属于当时的静态站发布。Blog 内容 Hook 仍需补齐或核对一次性配置,并留下一次真实内容更新的端到端验收记录;后续 Clerk、Convex、AI Search 的生产配置与实际功能也应按各自上线记录验证。本文记录流程及证据边界,不把脚本已经实现等同于所有外部配置已经生效。
Codex 与 GPT-6 Astra 在这次开发中的作用
这次工作也是一次使用 GPT-6 Astra 持续完成真实工程任务的实践。截至本文记录时,OpenAI 已在官方模型资料中列出 GPT-6 Astra,并将它定位为面向困难端到端工作的模型;官方模型选择文档也列出了相应标识。GPT-6 Astra 模型说明、官方模型列表
在这个项目中,值得记录的是它怎样与 Codex 的工具环境配合:连续阅读不同仓库、修改代码、执行构建、打开页面验证,再根据中途追加的要求修正实现。模型提供推理和代码能力,文件、终端、浏览器、Git 和部署操作由 Codex 的工具与权限环境承接。
持续推进同一目标,并吸收具体纠正
需求并非一次性完整给出。实现过程中,陆续明确了“不把业务页放进主题”“主题不依赖 HeroUI”“只保留一个 Worker”“归档分类应页内滚动”等要求。
Codex 需要把这些新条件带回已经写好的实现,并继续处理受影响的配置、文档和验证。最典型的是搜索:先让两个站点都能搜索,随后进一步明确共同实现应归主题,于是继续收敛依赖和构建职责,而不是只修改一处搜索框。
GPT-6 Astra 的官方指南强调长任务与多步骤工具协作。本项目提供的是这种工作方式的一次具体实例,不能据此给出与其他模型相比的速度或质量倍数。GPT-6 Astra 使用指南
并行审查负责找差异,主任务负责整合
可以独立开展的检查被拆成并行任务,例如旧主题复用范围、内容兼容、主题示例是否独立、搜索实现和开发规则对照。主任务结合这些结果继续实现和修正。
适合并行的是边界清晰的调查与审查。相互依赖的修改、部署和最终验收仍需按顺序完成。多个检查任务也不能替代最终产物验证:某个组件文件看起来正确,不代表它打包后可被独立项目使用。
人的 review 提供了构建日志没有的信息
侧栏宽度、周刊卡片、滚动条占位、标签间距和导航位置,都是在 review 中被具体指出并修正的。曾经额外加入的“最近修改”列表也说明,Agent 可能做出超出预期的设计判断。
有效的反馈不是泛泛地说“再优化一下”,而是提供可比较的条件:与旧版哪个值一致、点哪个链接应在何处滚动、哪些页面属于主题、哪些属于博客。随后让 Codex 定位实现,并把结果放回页面检查。
本次实践中,多轮修改能够围绕同一目标持续推进,但验收标准依然需要明确。本次采用 ultra 是任务运行配置,不意味着所有维护任务都应该使用相同推理投入。
将纠正沉淀为规则,而不是只留在对话里
迁移结束后,旧 hugo-book 分支中的开发规则被带回新 main,并更新技术入口。保留的重点是 URL、评论、内容边界和检查要求。
后续再让 Codex 修改主题或业务页面时,它应能从仓库说明中知道:主题不能依赖商业组件,构建不能回写内容,普通预览产物不能上线,Giscus 的路径约定不能随意改变。这样的规则为持续协作提供可读取的依据,也便于人在代码 review 时检查是否被遵守。
完成到什么程度,以及接下来继续做什么
下面是本轮迁移及搜索收敛使用固定内容快照时的验收记录,数量不是站点未来的永久指标:
| 验收项目 | 本轮结果 |
|---|---|
| 历史路由 | 保留全部 1,208 条旧 URL |
| 关键正文能力 | 检查覆盖 951 个评论页、25 个公式页、65 个 Mermaid 页和 623 个代码页 |
| 导航与布局 | 102 个可见导航分组与旧产物顺序一致;检查 390、1920、2560px 等视口 |
| 最后搜索整合的测试 | 博客 26 项、主题 33 项测试通过 |
| 搜索内容对照 | 968 条新旧记录的 URL、正文和元数据一致 |
| 生产 HTTP 抽查 | 23 个页面、34 条跳转、23 项资源通过检查 |
| 独立主题消费 | 打包安装后的示例能构建,子路径下搜索可用 |
这些结果表明迁移中的路由、功能和部署检查已完成,不能替代长期流量观察或性能基准。主题代码已可独立使用,博客也已切到 Astro 生产版本。
接下来仍有明确的增量空间:
- 将外部 Blog 的 MDX 内容和组件引用接入受控构建,让交互文章更直接地随内容维护。
- 继续增加 Vue、Three.js 等独立实验,根据实际需要决定隔离与资源加载方式。
- 在单独任务中处理历史外链、引用及已记录的原文图表问题。
- 为普通文章和重 demo 建立性能测量,特别关注客户端代码高亮的加载与主线程成本。
- 按需完善主题版本发布与上游功能跟进;补齐 Blog 内容 push 经 Deploy Hook 到线上更新的验收记录,并持续验证新增服务的生产发布链路。
这次迁移已经把熟悉的阅读界面保留下来,也建立了可持续加入前端组件的工程结构。后续功能可以分别落在内容、主题和站点业务中,并沿用同一套兼容与验收规则继续迭代。