跳至正文
Yukihime

AstroBlog 开发与维护指南

AstroBlog 开发与维护指南

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

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

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

运行环境和依赖边界

AstroBlog 要求 Node.js >=22.19.0,使用 pnpm 9.14.4,核心技术栈为 Astro 7、Svelte 5、Tailwind CSS 4 和 Swup 4。MDX、Shiki、KaTeX、Pagefind 和 Sharp 分别负责组件化文章、构建期代码高亮、公式、搜索和图片处理。依赖声明以 package.json 为准,实际安装版本由 pnpm-lock.yaml 锁定,排查兼容性时应核对这两个入口。

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

目录结构

Text
src/
├─ components/       公共、页面、功能和后台组件
├─ config/           站点、导航、侧栏、页面和管理员配置
├─ content/          文章、动态、书籍、友链等内容文件
├─ layouts/          Layout、MainGridLayout、ReadingLayout、AdminLayout
├─ pages/            Astro 文件路由和 API 静态端点
├─ plugins/          Markdown、图片、Mermaid 和构建插件
├─ scripts/          评论管理和音乐后台交互脚本
├─ styles/           reset、tokens、base、components、pages、admin
├─ utils/            内容查询、URL、图片、主题和运行时工具
└─ workers/          主站 GitHub 写入代理
workers/
└─ comments/         评论、音乐、首页视频 Worker 与 D1/R2
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 卡片和标题锚点。

代码块由 rehype-markdown-code.mjs 使用 Shiki 的 github-light 高亮,支持文件名、行号、标记与折叠,复制和换行由 code-block-controls.ts 增强。rehype-content-boundaries.mjs 将新代码组件限定在文章与友链本站信息;文章标题锚点与 GitHub 卡片也按文章来源隔离。共享 Markdown 保留原有行为,Expressive Code 及其配置已移除。插件顺序有依赖,例如 rehypeRaw 影响后续节点插件,图片和 Mermaid 也需要在正文进入组件前完成转换。新增 Markdown 语法时,应该在 processor 中加入插件并补测试,不要在单个文章组件里用正则解析全文。

全局布局

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

src/layouts/MainGridLayout.astro 组合 Navbar、Banner、左右侧栏、主内容和 Footer,并根据 sidebarLayoutConfig、页面类型和响应式断点生成网格类。这些配置继续服务普通页面;文章详情已改用 ReadingLayout.astro 的独立文档,保留左侧目录和右下角阅读工具。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,在 ReadingLayout.astro 中交给 ArticleHero.astro、ArticleContent.astro、目录、评论和 SEO 组件。文章图片在 Markdown 阶段由 src/plugins/article-images/ 解析相对路径,不能在浏览器运行时拼接源文件路径。

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

前端样式、主题和 Swup

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

文章详情单独加载 src/styles/pages/reading.css 与 tokens/reading.css,固定白色,不加载普通页面主题或壁纸脚本,不读写主题偏好。字体沿用 fonts.css 与 tokens/typography.css,几何与层级也共用既有令牌。普通共享 Markdown 不受文章富内容样式影响,友链本站信息代码块是唯一例外。

Swup 配置替换普通页面主内容、Banner 和动态侧栏容器,后台、音乐页和文章阅读文档被忽略。进出文章以及跨布局前进后退采用完整页面导航,返回普通页面恢复原主题偏好。主布局脚本需要区分点击、content:replace 和 page:view:点击阶段只处理反馈,替换后同步路径和布局,页面可见后初始化目录、评论、Mermaid 和页面专用脚本。需要反复执行的监听器使用 AbortController 或 cleanup,避免页面切换后重复绑定。

工程规范与文章样式边界统一见仓库 AGENTS.md。修改样式运行 pnpm verify:styles 和 pnpm check;修改主题、壁纸或 Swup 还要运行桌面浏览器回归检查,覆盖不同桌面窗口宽度、键盘焦点和页面前进后退。前台保留蓝白与粉白主题,后台继续使用独立的主题覆盖。

管理后台和 GitHub 写入

后台页面集中在 src/pages/admin/,文章功能主要由 src/components/admin/posts/PostManager.svelte 和 src/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,后台必须刷新预览,不能覆盖新版本。

后台文章与规划预览经 src/utils/adminPreview.ts 清理 HTML,移除活动内容和不允许的属性;预览是编辑辅助,不是完整 Astro/MDX 编译。代理还拒绝编码分隔符与点路径等绕过,不能只检查未经规范化的 URL。

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

评论、音乐和首页视频 Worker

workers/comments/ 按路径分发评论、音乐和首页视频接口。评论和音乐目录使用 D1 waline-comments,音乐对象与首页视频分别使用 MUSIC_BUCKET 和 HOME_VIDEO_BUCKET 两个 R2 绑定。评论表通过 migration 管理,回复用 parent_id 建树;公开接口按审核状态过滤,管理员接口要求 token。评论图片使用 multipart,Worker 检查 WebP 文件头、声明长度、尺寸、数量和大小后才写入 D1。

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

首页视频由 homeVideos.ts 读取媒体 R2 的 home/ 目录,并通过 /api/home-videos 返回启用的视频、播放规则和配置版本。后台壁纸管理使用受保护的管理员接口上传视频、调整顺序和保存规则;配置保存使用 revision 与 R2 ETag 校验,遇到并发修改返回 409。前台播放器优先使用在线清单,接口不可用时回退缓存或内置候选,页面导航和正文不依赖视频请求成功。

AI 页面、助手、摘要、后台与独立 Worker,以及访客洞察和采集均已退役。clearRetiredBrowserData.ts 定向清理旧存储,Worker 对访客旧路径返回退役状态;迁移 0018_remove_visitor_insights.sql 删除访客表,保留评论共用数据库、密钥、反滥用与清理 Cron。自动日志的退役文案由 scripts/changelog-sync/history-policy.json 管理。

BlogRoom 数据生成

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

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

构建流程

AstroBlog 的 pnpm build 顺序大致为:

Text
verify:secrets
  → verify:post-tags / verify:styles
  → verify:comments / verify:runtime-utils / verify:home-wallpaper
  → verify:article-content
  → generate-room-data
  → prepare-build
  → generate-font-css / generate-icons
  → astro build
  → pagefind --site dist
  → normalize generated fonts

页面数量和搜索索引数量随公开内容变化,以本次构建日志为准。构建输出中的空可选集合提示不是失败;真正失败通常来自 Schema、Markdown 插件、图片、环境变量或生成脚本。构建成功后可运行 pnpm verify:pagefind 核对公开页面的索引范围,但远程 Worker、D1、R2、GitHub 权限和浏览器交互仍需分别验收。

修改矩阵

想修改的内容首先查看必须同步检查
首页模块src/pages/[...page].astro、HomeHero.astro布局、百叶窗、首页视频和桌面交互
页面外壳src/layouts/Layout.astro、MainGridLayout.astroSwup、主题、侧栏和 SEO
导航/侧栏navBarConfig.ts、sidebarConfig.ts对应组件、响应式和页面类型
文章字段content.config.tsFrontmatter、查询层、后台编辑器
文章列表content-utils.ts、PostPage.astro排序、分页、瀑布流和空状态
文章详情[...slug].astro、ReadingLayout.astro、components/pages/posts/固定白色、共享字体、双目录、整页导航、图片与 SEO
普通主题与文章样式main.css / pages/reading.css 及各自令牌蓝白/粉白、固定白色阅读、后台边界与共享字体角色
GitHub 写入github-proxy.js白名单、认证、分支保护、验证脚本
评论/音乐workers/comments/migration、前端组件、管理面板
首页视频homeVideos.ts、homeWallpaperPlayer.tsR2 清单、播放规则、壁纸管理和回归测试
BlogRoom 数据generate-room-dataBlogRoom 同步脚本、类型和快照

本地启动、检查和排错

powershell
# 安装依赖并启动 Astro 开发服务器。
corepack pnpm install
corepack pnpm dev
# 检查 Astro 模板、Content Collections 和样式契约。
corepack pnpm check
# 验证后台格式、草稿、认证和 GitHub 写入规则。
corepack pnpm verify:admin
# 验证评论路径、首页视频与退役端点。
corepack pnpm verify:comments
# 验证 Markdown/MDX 编译、代码与富内容。
corepack pnpm verify:article-content
# 执行完整静态构建、资源生成和 Pagefind 索引。
corepack pnpm build

浏览器回归先准备最新 dist/ 和 Chrome/Chromium。可按需运行 pnpm verify:browser --article-reading-only、--content-boundary-only 或 --admin-preview-only,完整选项见仓库 scripts/README.md。pnpm build:verify 在构建后扩展产物与性能检查,pnpm quality 聚合代码质量与依赖安全检查;这些是验证入口,不表示本文更新时全部执行通过。

文章没有显示时,可以先检查 Frontmatter、草稿状态和集合配置。接口报错就看浏览器 Network 和 Worker 日志;发布后页面没更新,再核对 Cloudflare 的构建记录和部署日志。

[ 公告 ]

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

了解更多
[ 音乐 ]
封面

音乐

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