博客主题对标后的六项核心改进记录
这次改造并没有从视觉层面入手,而是先拿博客和 Astro 官方 Themes 里的几个成熟博客主题做了一次横向对标,样本包括 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 传给 Layout 和 BaseHead。
也就是说,显式写了 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 现在会输出 body 和 excerpt 字段,src/components/SearchModal.astro 则把 Fuse.js 的 keys 扩展成标题、描述、标签和正文。搜索结果展示时,也会优先从命中的描述、摘要或者正文里截取片段。
这次没有直接引入 Pagefind。缘由是当前 Fuse.js 搜索链路已经存在,先在原链路上补正文索引,改动面更小,验证成本也更低。后续如果文章数量继续增长,再切换到 Pagefind 会更有依据。
代码块体验补齐
代码块这次没有上 Expressive Code,而是在现有 Shiki 管线里做增强。核心点是保留代码块 meta:astro.config.mjs 里增加了 Shiki transformer,当代码块实际带 meta 时,会把原始 meta 写入 pre 的 data-meta 属性。
这里有一个实际踩过的坑:Shiki 当前上下文里可用的是 this.options.meta.__raw,不是一开始直觉上会去找的 this.meta.__raw。只有拿到这段原始 meta,前端组件才知道标题、文件名和行高亮这些信息。
现在 src/components/CopyCodeButton.astro 不单负责复制,还会增强代码块展示:
- 显示代码语言;
- 支持
title或filename; - 支持
{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-check | 0 errors;最终汇总保留 18 条 hints |
npm run test | 1 个测试文件、6 个用例通过 |
npm run build | 172 page(s) built in 14.37s |
产物层面也做了几项抽查:
| 抽查项 | 结果 |
|---|---|
/archive | dist/archive/index.html 存在 |
search.json | 包含 43 篇文章,且有 body 与 excerpt 字段 |
CrashDetector | 生产 HTML 没有引用该组件脚本 |
| KaTeX | 样式只出现在检测到数学内容或显式启用数学的页面 |
| 文章 OG 图 | 带 heroImage 的文章输出文章级 Open Graph/Twitter 图片 |
| 代码块属性 | 构建产物中的代码块可见 data-language;data-meta 输出逻辑由带 meta 的代码块触发 |
这次没有做什么
评论系统没有纳入这批修改。它确实是很多博客主题的常见能力,但对当前站点来说,评论涉及公开交互、审核和备案风险,默认接入线上并不是低风险决策。后续更适合做成一个本地可验证、配置可开启、线上默认关闭的可选能力。
i18n 也没有做。当前内容主要面向中文读者,多语言路由会明显增加内容维护成本,不太适合在这次质量修复里顺手展开。
最后,模板配置层也没有在这批改动里重构。站点级配置收敛值得做,但它会影响公开模板、README、同步脚本和部署说明,应该单独规划。