暂不支持移动端访问

AstroBlog 开发与维护指南

2926 字 15 分钟
AI 摘要

从 Astro 页面、Content Collections、样式、管理后台、Cloudflare Worker 到构建部署,完整说明 AstroBlog 的代码架构。

AstroBlog 是一个以 Astro 静态生成为核心的个人站点。Markdown/MDX Content Collections 是公开内容源,Astro 页面和组件负责生成 HTML,Svelte 负责后台和少量有状态交互;评论、访客、音乐、AI 和 GitHub 写入则由 Cloudflare Worker 提供运行时能力。站点的关键不是某个框架,而是明确区分构建时数据、浏览器状态和边缘服务。

本文是项目的代码级维护入口。需要修改功能时,应先确定它属于内容、页面、样式、浏览器脚本、后台、Worker 还是构建脚本,再进入对应目录。不要从最终生成的 dist/ 反推源代码,也不要把运行时 API 逻辑塞进 Astro 页面。

运行环境和依赖边界#

AstroBlog 当前使用 Node.js 24.18.0 和 pnpm 9.14.4。核心依赖包括 Astro 6.4.6、@astrojs/mdx 6.0.3、@astrojs/svelte 8.1.2、Svelte 5.56.4、Swup 4.9.2、Tailwind CSS 4.3.2、Three.js 0.184、Expressive Code 0.43.1、KaTeX 0.16、Pagefind 1.5.2 和 Sharp 0.34。

依赖按职责分为几层:Astro 和 Content Collections 负责静态页面与内容;Svelte 负责后台表单和管理状态;Swup 负责主站页面切换;Tailwind、分层 CSS、Iconify 和字体包负责视觉;remark/rehype、Expressive Code、KaTeX、Mermaid 负责 Markdown 处理;Pagefind 负责构建后的站内搜索;Cloudflare Worker、D1 和 R2 负责需要运行时状态的服务。

目录结构#

text
src/
├─ components/ 公共、页面、功能和后台组件
├─ config/ 站点、导航、侧栏、页面和管理员配置
├─ content/ 文章、动态、书籍、友链等内容文件
├─ layouts/ Layout、MainGridLayout、AdminLayout
├─ pages/ Astro 文件路由和 API 静态端点
├─ plugins/ Markdown、图片、Mermaid 和构建插件
├─ scripts/ 浏览器端追踪和页面交互脚本
├─ styles/ reset、tokens、base、components、pages、admin
├─ utils/ 内容查询、URL、图片、主题和运行时工具
└─ workers/ 主站 GitHub 写入代理
workers/
├─ comments/ 评论、访客、音乐 Worker 与 D1/R2
└─ ai/ AI Worker 与独立 D1
scripts/ 构建、数据同步、验证和生成工具
public/ 原路径输出的静态资源和 BlogRoom 快照

源文件和生成文件要分开看。src/constants/icons.ts、字体 CSS 和 public/room-data/*.json 可以由构建脚本重新生成,不应该手工修改;src/content/src/config/src/pages/src/components/ 和 Worker 源码是实际修改入口。

Astro 配置和 Markdown 管线#

astro.config.mjs 设置静态输出、站点 URL、尾斜杠、旧路径重定向、Svelte/MDX/Swup/Icon/Sitemap 集成和 Vite 构建选项。Markdown processor 使用 unified:remark 阶段处理数学公式、阅读时间、摘要、指令、分节和 Mermaid;rehype 阶段处理 KaTeX、提示框、标题 slug、图注、外链、邮箱保护、GitHub 卡片和标题锚点。

Expressive Code 负责代码框、行号、折叠区域和复制按钮,主题由 [data-theme] 选择器切换。插件顺序有依赖,例如 rehypeRaw 影响后续节点插件,图片和 Mermaid 也需要在正文进入组件前完成转换。新增 Markdown 语法时,应该在 processor 中加入插件并补测试,不要在单个文章组件里用正则解析全文。

全局布局#

src/layouts/Layout.astro 生成完整 HTML、head 元数据、字体和首屏初始化脚本。它读取站点标题、语言、主题色、壁纸模式和页面路径,把初始主题、Banner 高度和首页视频域名注入内联脚本。页面可见后,setting-utils.ts 接管主题、壁纸和 localStorage 同步。

src/layouts/MainGridLayout.astro 组合 Navbar、Banner、左右侧栏、主内容和 Footer,并根据 sidebarLayoutConfig、页面类型和响应式断点生成网格类。文章页可以临时显示对侧栏,隐藏侧栏或允许内容溢出都由布局 props 决定。AdminLayout.astro 是独立骨架,不加入主站 Swup 容器。

首页根路由和内容模块在 src/pages/[...page].astro,首页 Hero 位于 src/components/layout/HomeHero.astro,导航配置在 src/config/navBarConfig.ts,侧栏顺序和显示条件在 src/config/sidebarConfig.ts。修改首页模块顺序不要直接移动布局层的 DOM,先确认该模块属于页面内容还是公共外壳。

文章内容系统#

src/content.config.ts 当前定义 13 个集合。文章集合通过 glob loader 读取 src/content/posts/ 下的 .md.mdx,排除 _fixtures;Schema 使用 astro/zod 校验 title、published、draft、description、tags、category、layout、image、pinned、comment、order 等字段。

text
src/content/posts/*.md(x)
↓ loader + Zod
CollectionEntry<"posts">
content-utils.ts
文章列表 / 详情 / 归档 / 分类 / 标签 / 搜索

getPublicPosts() 排除 draft: true 和 fixture;getSortedPosts() 按置顶、日期和同日 order 排序,并补充上一篇/下一篇;getSortedPostsList() 删除正文,只给列表页面提供 metadata。文章列表路由是 src/pages/posts/[...page].astro,卡片组件是 src/components/layout/PostCard.astro,详情路由是 src/pages/posts/[...slug].astro

文章详情通过 render(entry) 输出正文组件和 headings,再交给 ArticleHero.astroArticleContent.astro、目录、评论和 SEO 组件。文章图片在 Markdown 阶段由 src/plugins/article-images/ 解析相对路径,不能在浏览器运行时拼接源文件路径。

文章列表为空时的排查顺序是:文件扩展名 → Frontmatter → draft_fixtures → collection loader → getPublicPosts() → 构建使用的内容版本 → 部署页面。不要先改分页组件。

前端样式、主题和 Swup#

全局 CSS 入口是 src/styles/main.css,只负责导入和层顺序。当前层顺序为 theme, reset, tokens, base, components, utilities, overrides;颜色、字体、间距、圆角和 z-index 等语义值放在 src/styles/tokens/。公共组件样式、页面样式和后台样式分开,组件应消费 var(--card-bg) 等语义变量而不是重复十六进制值。

Swup 配置替换主内容、Banner 和动态侧栏容器,后台、音乐页和独立页面被忽略。主布局脚本需要区分点击、content:replacepage:view:点击阶段只处理反馈,替换后同步路径和布局,页面可见后初始化目录、评论、Mermaid 和页面专用脚本。需要反复执行的监听器使用 AbortController 或 cleanup,避免页面切换后重复绑定。

修改样式运行 pnpm verify:styles;修改主题、壁纸或 Swup 还要运行浏览器回归检查。样式层级正确不代表移动端、键盘焦点和页面后退行为正确。

管理后台和 GitHub 写入#

后台页面集中在 src/pages/admin/,文章功能主要由 src/components/admin/posts/PostManager.sveltesrc/components/edit/WriteEditor.svelte 提供。AdminLoginGate.svelte 处理管理员会话和 X-Admin-Token,Manager 负责列表、表单、预览、上传和状态。

文章内容由 src/utils/adminContent.ts 局部修改 Frontmatter,尽量保留字段顺序、注释、换行和正文。发布链路为:

text
WriteEditor.svelte
→ adminContent.ts
→ AdminLoginGate / X-Admin-Token
→ /api/github
→ src/workers/github-proxy.js
→ GitHub Contents / Git Data API
→ Cloudflare 构建
→ Content Collections 生成页面

github-proxy.js 是写入安全边界。它检查来源、管理员授权、请求体大小、允许的仓库和分支、路径白名单、HTTP 方法和生产分支保护;批量内容操作还会验证分支 HEAD、文件 blob SHA、文件数量、单文件大小和总 payload 大小。远程文件发生变化时返回 409,后台必须刷新预览,不能覆盖新版本。

新增可写资源时要同步 Manager 数据模型、adminContent.ts、代理白名单、方法限制和 verify-admin 脚本。后台发布返回成功只代表仓库写入成功,公开页面还要等待 Cloudflare 完成新的静态构建。

评论、访客和音乐 Worker#

workers/comments/ 同时处理评论、访客和音乐接口,绑定 D1 waline-comments 和音乐 R2。评论表通过 migration 管理,回复用 parent_id 建树;公开接口按审核状态过滤,管理员接口要求 token 或 owner cookie。评论图片使用 multipart,Worker 检查 WebP 文件头、声明长度、尺寸、数量和大小后才写入。

访客代码在 workers/comments/src/visitors.tsvisitor_profilesvisitor_visitsvisitor_visit_pages 分别表示浏览器归并身份、一次访问和页面事件;设备 ID 和 visit token 用哈希验证,IP 相关字段用 AES-GCM 加密,清理任务按 VISITOR_RETENTION_DAYS 删除过期数据,单次访问最多 256 个 pageview。src/scripts/visitorTracker.ts 采用空闲加载,Swup 导航后批量上报 pageview。

音乐目录和音频对象也在 comments Worker 中处理,D1 保存目录元数据,R2 保存音频、封面和歌词。修改音乐字段时要同时检查 music handler、migration、管理端和播放器状态。

AI Worker#

workers/ai/ 是独立 Worker,绑定 D1 yukihime-aiindex.ts 负责编排路由、管理员上下文、凭据、知识检索、用量和审计,providers.ts 负责供应商请求和错误映射。API key 以主密钥加密保存,管理端只看到标签、模型、状态和末四位。

scripts/sync-ai-index/index.mjs 将文章、导航等内容生成摘要、正文、路径、发布时间和内容哈希,写入 ai_documents。查询只取可见匹配文档,不把整个仓库直接塞进提示词。管理员 proposal 模式要求返回受限 JSON,执行前仍需重新验证 GitHub HEAD、目标 blob、路径白名单和精确 before 文本;AI 只能提出修改建议,不能绕过 GitHub Proxy 自动发布。

BlogRoom 数据生成#

AstroBlog 构建时运行 scripts/generate-room-data/index.mjs,从 src/content/bangumi/src/content/friends/ 生成 public/room-data/books.jsonfriends.json。BlogRoom 构建前通过 scripts/sync-room-data.mjs 获取线上数据,失败时依次回退本地 AstroBlog 快照和已有快照,并验证 version、数组和字段。

修改书籍或友链内容时,源文件在 AstroBlog;生成 JSON 是构建产物;BlogRoom 的 src/config/room-data/ 是同步后的快照。三个位置的字段必须保持兼容,不能直接手工改 BlogRoom 快照来“修复”线上内容。

构建流程#

AstroBlog 的 pnpm build 顺序大致为:

text
verify:secrets
→ verify:styles
→ verify:comments / runtime-utils / home-wallpaper
→ generate-room-data
→ prepare-build
→ generate-font-css / generate-icons
→ astro build
→ reconcile generated assets
→ pagefind --site dist
→ normalize generated fonts

当前完整构建已生成 89 个页面,Pagefind 索引 64 个页面。构建输出中的空可选集合提示不是失败;真正失败通常来自 Schema、Markdown 插件、图片、环境变量或生成脚本。构建成功也不代表远程 Worker、D1、R2、GitHub 权限或浏览器交互已经通过端到端验收。

修改矩阵#

想修改的内容首先查看必须同步检查
首页模块src/pages/[...page].astroHomeHero.astrositeConfig、布局、首页视频和移动端
页面外壳src/layouts/Layout.astroMainGridLayout.astroSwup、主题、侧栏和 SEO
导航/侧栏navBarConfig.tssidebarConfig.ts对应组件、响应式和页面类型
文章字段content.config.tsFrontmatter、查询层、后台编辑器
文章列表content-utils.tsPostPage.astro排序、分页、瀑布流和空状态
文章详情[...slug].astrocomponents/pages/posts/图片、目录、评论、SEO
颜色和字体src/styles/tokens/浅色/深色、后台、样式契约
GitHub 写入github-proxy.js白名单、认证、分支保护、验证脚本
评论/访客workers/comments/migration、前端 tracker、管理面板
AIworkers/ai/provider、D1、索引、proposal、测试
BlogRoom 数据generate-room-dataBlogRoom 同步脚本、类型和快照

本地启动、检查和排错#

Terminal windowpowershell
# 安装依赖并启动 Astro 开发服务器。
corepack pnpm install
corepack pnpm dev
# 检查 Astro 模板、Content Collections 和样式契约。
corepack pnpm check
# 验证后台格式、草稿、认证和 GitHub 写入规则。
corepack pnpm verify:admin
# 运行评论、访客和图片相关 Worker 测试。
corepack pnpm verify:comments
# 验证 AI provider、索引和提案流程。
corepack pnpm verify:ai
# 执行完整静态构建、资源生成和 Pagefind 索引。
corepack pnpm build

文章或 Schema 修改先运行 check;后台修改运行 verify:admin;评论、访客或图片修改运行 verify:comments;AI 修改运行 verify:ai;涉及构建、资源或路由时运行完整 build。远程 Worker 可以使用 comments:devai:dev 和 Wrangler migration 命令单独启动。

排错时先看错误发生在哪一层:内容未生成看 collection 和 Frontmatter;页面结构错误看 route/layout/component;主题和过渡错误看 tokens、Layout 和 cleanup;请求失败看浏览器 Network、src/api 和 Worker 日志;后台发布失败看代理白名单、认证和分支 HEAD;线上页面旧看 Cloudflare 构建 commit、dist/build-version.json 和部署日志。

截至当前工作树,src/content/posts/ 共有 18 个 Markdown/MDX 文件,全部为公开文章,其中 3 篇系统测试文章位于时间线最早位置;_fixtures 中的回归样本不进入公开集合。源码、构建产物和远程服务各有独立生命周期,维护时必须从源文件开始确认,而不是只看浏览器最终页面。

[ 公告 ]

如果你喜欢,那么欢迎来到我的世界!

了解更多
[ 音乐 ]
封面

音乐

找不到相关结果。
[ 目录 ]
[ 全部文章 ]