全部文章

这个博客的技术选型与取舍

GitHub Pages 没有服务端。能在构建期做完的事,就不要留到运行期:内容层、字体、OG 都按这条砍。

手绘:构建期里叠着内容层、字体和 OG 三张稿纸

主题

重构这个站点时,判断标准只有一条:能不能在构建期做完的事,就不要留到运行期。

GitHub Pages 是纯静态托管,没有服务端。这个约束让选择变清楚,而不是变穷。

案例

Astro 6 去掉了约定式内容集合。旧代码里的 post.slugpost.render() 一起失效。迁移不是换个配置文件名,是条目标识和渲染 API 两处一起断。

同时,标题如果继续吃系统字体,同一篇文章在 macOS 和 Windows 上是两种气质。外链 Google Fonts 能统一,但首屏会多一个第三方域名。

这两件事都发生在「站点已经能发文章」之后。该补的是构建期能力,不是运行时花活。

观点

GitHub 文档把 Pages 定义成静态托管,并写明不跑 PHP、Ruby、Python 这类服务端语言。静态托管上,高级感来自敢删:Server Islands 做不了,全站搜索在文章很少时不值得,评论要引入第三方脚本。留下的四件事——内容层、字体、分发出口、OG 图——都必须在 astro build 里结束。

内容主线已经在Markdown 那篇锁死。这篇只谈工程层怎么把那条主线托住。

实操

内容层改显式 loader

配置从 src/content/config.ts 搬到 src/content.config.ts,范围用 glob() 写死:

src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const posts = defineCollection({
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/posts' }),
schema: z.object({
title: z.string(),
pubDate: z.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
});
export const collections = { posts };

迁移时真正会踩的两处:post.slug 改成 post.id;渲染从实例方法变成顶层 render()headings 顺手就是右侧目录,不必自己解析 HTML。

字体自托管

astro.config.mjs
fonts: [
{
provider: fontProviders.google(),
name: 'Newsreader',
cssVariable: '--font-display-latin',
subsets: ['latin'],
},
]

构建期下载并生成 @font-face。中文按 unicode-range 切片,浏览器只取当前页用到的那几块。

四个出口一次齐

  • RSS:/rss.xml
  • sitemap:给爬虫
  • JSON-LD:告诉搜索引擎这是 BlogPosting
  • OG 图:构建期用 satori + resvg 画,中文按标题字符取子集,不要整包 CJK
Terminal window
npm i satori @resvg/resvg-js

总结

有些能力明确不做:

能力 结论
Server Islands 静态托管没有服务端,做不了
全站搜索 文章少时用不上,等内容够了再说
评论系统 引入第三方脚本的代价大于收益

工程上大部分「高级感」不来自加了什么,而来自敢删掉什么。

写作本身怎么避免每篇从零发明,见把写博客做成一个 skill

参考

  1. What is GitHub Pages?(查阅 2026-09-14)— Pages 是静态托管;文档写明不支持 PHP / Ruby / Python 这类服务端语言。

系列 · 这个博客本身

第 3 / 4 篇
  1. 01我的技术博客正式上线
  2. 02为什么选择 Markdown 作为内容主线
  3. 03这个博客的技术选型与取舍
  4. 04把写博客做成一个 skill

相关阅读

选择 打开esc 关闭