博客主题对标后的六项核心改进记录

博客主题对标后的六项核心改进记录

这次改造不是从视觉开始,而是先把博客和 Astro 官方 Themes 中几个成熟博客主题做了一次横向对标。对标报告放在 docs/ASTRO_OFFICIAL_BLOG_THEME_COMPARISON.md,样本包括 Retypeset、AstroPaper、Tone、Aonote、Chirping Astro 和 Basic Blog。

对标后能看出来:当前站点已经具备基础能力,优先要补的是生产质量、资源加载粒度、分享质量、全文搜索、技术写作体验和文章信息架构这几类低风险改进。因此这次只收敛到六项改动,没有把评论、i18n 或模板配置重构一起塞进来。

先处理生产质量问题

第一项是 CrashDetector。它本来是调试用组件,但文章布局会默认渲染它。调试组件进入生产页面会带来不必要的脚本、定时器和控制台输出,所以现在 src/layouts/BlogPost.astro 里通过 import.meta.env.DEV 控制,只在开发环境渲染。

这个改动的取舍很直接:调试能力保留,但不默认进入线上文章页。它符合 YAGNI,也避免让每篇文章都背上调试组件的运行成本。

第二项是 KaTeX 样式按需加载。之前 BaseHead.astro 静态引入 katex/dist/katex.min.css,即使非数学文章也会带上这份样式。现在 src/content.config.ts 增加了可选的 math frontmatter,src/layouts/BlogPost.astro 同时会检测正文中常见数学语法,再把结果作为 showKaTeX 传给 LayoutBaseHead

也就是说,显式写 math: true 的文章会加载 KaTeX 样式;没有写时,布局会根据正文是否包含数学公式做兜底判断。这样不会要求每篇旧文章都立刻补字段,也能让普通文章保持更轻。

文章分享图回到文章级

BaseHead.astro 原本已经支持 image,但中间的 Layout.astro 没有把这个 prop 暴露出来,文章页也没有把 heroImage 传到 head。结果是文章详情页容易回退到默认分享图。

这次把链路补齐了:BlogPost.astro 将文章的 heroImage 传给 Layout.astro,再由 Layout.astro 传给 BaseHead.astro。无图文章仍然走默认 fallback,有图文章则可以在 Open Graph 和 Twitter Card 中使用自己的封面图。

这是一个小改动,但会影响文章被分享出去时的呈现。文章列表、详情页和分享卡片看到的主图不再脱节。

搜索从元数据扩展到正文

原来的搜索更像元数据搜索:标题、描述和标签能搜,但正文里的关键内容搜不到。对技术博客来说,这会明显降低可用性,因为很多检索动作其实是回忆某段实现、某个错误信息或某个配置项。

这次新增了 src/utils/searchText.ts,把 Markdown 正文清洗成适合索引的文本。它会去掉 frontmatter、代码块、图片、HTML 标签和大部分 Markdown 装饰,保留链接文本和行内代码文本。当前搜索正文最多保留 6000 个字符,摘要最多保留 220 个字符。

src/pages/search.json.ts 现在会输出 bodyexcerpt 字段,src/components/SearchModal.astro 则把 Fuse.js 的 keys 扩展为标题、描述、标签和正文。搜索结果展示时也会优先从命中的描述、摘要或正文里截取片段。

这次没有直接引入 Pagefind。原因是当前 Fuse.js 搜索链路已经存在,先在原链路上补正文索引,改动面更小,验证成本也更低。后续如果文章数量继续增长,再切到 Pagefind 会更有依据。

代码块体验补齐

代码块这次没有上 Expressive Code,而是在现有 Shiki 管线里做增强。核心点是保留代码块 meta:astro.config.mjs 里增加了 Shiki transformer,把原始 meta 写入 pre[data-meta]

这里有一个实际踩坑:Shiki 当前上下文里可用的是 this.options.meta.__raw,不是一开始直觉上会找的 this.meta.__raw。只有拿到这段原始 meta,前端组件才知道标题、文件名和行高亮信息。

现在 src/components/CopyCodeButton.astro 不只负责复制,还会增强代码块展示:

  • 显示代码语言;
  • 支持 titlefilename
  • 支持 {1,3-5} 这样的行高亮;
  • diff 代码块里的新增行和删除行做样式区分;
  • 避免 Astro 页面切换或动态内容导致重复初始化。

以后写文章时可以这样标注代码块:

```typescript title="demo.ts" {1,3-5}
const value = 1;
console.log(value);
```

这仍然是一个相对克制的实现。它没有引入新的 Markdown 组件体系,只是在现有代码高亮和复制按钮基础上补齐最常用的技术写作能力。

补上归档页

站点原来有首页、博客列表、标签页和 Blog Galaxy,但缺少一个按时间回看文章的低干扰入口。这次新增了 /archive,实现文件是 src/pages/archive.astro

归档页复用 getSortedPublishedPosts(),按年份和月份聚合已发布文章。桌面导航和移动导航都在 src/components/Header.astro 中加入了“归档”,HeaderLink.astro 也补了 active 状态判断。

这类页面不复杂,但适合长期写作后的回看。标签页用于按主题找文章,归档页用于按时间查看项目变化,两者解决的问题不同。

验证结果

这次改造后已经跑过三类检查:

npm run type-check
npm run test
npm run build

结果如下:

检查项结果
npm run type-check0 errors;仍有既有 hints/warnings
npm run test1 个测试文件、6 个用例通过
npm run build168 pages built successfully

产物层面也做了几项抽查:

抽查项结果
/archivedist/archive/index.html 存在
search.json包含 41 篇文章,且有 bodyexcerpt 字段
CrashDetector生产 HTML 没有引用该组件脚本
KaTeX样式只出现在检测到数学内容或显式启用数学的页面
文章 OG 图heroImage 的文章输出文章级 Open Graph/Twitter 图片
代码块 metapre 上可以看到 data-languagedata-meta

这次没有做什么

评论系统没有纳入这批修改。它确实是很多博客主题的常见能力,但对当前站点来说,评论涉及公开交互、审核和备案风险,默认接入线上不是低风险决策。后续更适合做成本地可验证、配置可开启、线上默认关闭的可选能力。

i18n 也没有做。当前内容主要面向中文读者,多语言路由会显著增加内容维护成本,不适合在这次质量修复里顺手展开。

最后,模板配置层也没有在这批改动里重构。站点级配置收敛值得做,但它会影响公开模板、README、同步脚本和部署说明,应该单独规划。

数据验证清单

文章声明来源状态
本次改造依据 Astro 官方博客主题对标报告docs/ASTRO_OFFICIAL_BLOG_THEME_COMPARISON.md已验证
CrashDetector 仅在开发环境渲染src/layouts/BlogPost.astro已验证
KaTeX 由 showKaTeX 按需输出 stylesheetsrc/components/BaseHead.astrosrc/layouts/BlogPost.astro已验证
博客 frontmatter 支持可选 math 字段src/content.config.ts已验证
文章 heroImage 会传给 Open Graph/Twitter metasrc/layouts/BlogPost.astrosrc/layouts/Layout.astrosrc/components/BaseHead.astro已验证
搜索索引包含正文 body 和摘要 excerptsrc/pages/search.json.tssrc/utils/searchText.ts已验证
搜索弹窗会检索正文并展示命中片段src/components/SearchModal.astro已验证
代码块支持语言、标题/文件名、行高亮和 diff 行样式astro.config.mjssrc/components/CopyCodeButton.astro已验证
新增 /archive 并按年月聚合文章src/pages/archive.astro已验证
导航已接入归档页并支持 active 状态src/components/Header.astrosrc/components/HeaderLink.astro已验证
检查命令通过:type-checktestbuild实际命令输出记录已验证