这个博客是怎么搭的

·约 5 分钟

这一篇是写给你的——如果你 clone 了这个项目,它会告诉你东西都在哪。

你只需要改一个文件#

src/config.ts。里面的 site、author、nav 三项改完就能上线:

export const site: SiteConfig = {
  title: '你的站名',
  tagline: '一句话说清这个站是什么。',
  url: 'https://example.com',   // 部署前填,不留斜杠
  lang: 'zh-CN',                // 别改错——浏览器的中文标点规则依赖它
  author: { name: '你的名字', bio: '一句话介绍自己。' },
  // …
};

其余全部有可用的默认值,而且默认值本身就是完整站点,不是占位符。 你现在看到的这些文章和知识库条目就是示例内容——它们是真的能读的, 不是 lorem ipsum。删掉它们换成你自己的即可。

东西都在哪#

src/
├── config.ts            你唯一必须改的文件
├── content/
│   ├── posts/           文章。按时间排
│   └── wiki/            知识层。按主题互链
├── layouts/             页面骨架
├── components/          组件
├── pages/               路由
├── lib/                 纯逻辑(可测试,不依赖 Astro)
│   ├── negotiate/       Accept 头解析——[[内容协商]] 的实现
│   └── wiki/            链接图、体检、llms.txt 生成
└── styles/
    ├── tokens.css       设计令牌
    ├── base.css         基线排版(含 [[中文排版]] 的那些修正)
    └── site.css         布局与组件

两种内容,两种组织方式#

文章放在 src/content/posts/,按时间排列,是「流」。

知识库条目放在 src/content/wiki/,按主题互链,是「网」。

它们的区别不是格式,是读者找东西的方式:想看你最近写了什么就翻文章, 想搞清某个概念就查知识层。两边的条目地位相同,可以互相引用。

用 [[方括号]] 连起来#

在任何地方写 [[目标]],就会生成一条链接:

见 [[内容协商]] 一节。

支持三种写法:

写法效果
[[内容协商]]链接,显示文本即目标名
[[内容协商|那篇]]自定义显示文本
[[内容协商#为什么]]指向页内某小节

目标可以写 slug,也可以写标题——你大概不会记得每篇的 slug 是什么。 解析时大小写和空格都不敏感。

写错了不会静默失败:构建时会报一条 broken-wikilink 错误, 并告诉你哪个页面引用了什么。

构建时会做体检#

每次构建会跑一遍知识库体检,输出在控制台。分三级:

  • 错误:断链、两个页面抢同一个 URL、文章占用 /about/ 等系统路由、 引用了没登记的来源、复核状态与正文对不上。 会让构建失败(可在配置里关掉)
  • 警告:孤儿页(没有任何页面指向它)、缺摘要、空正文、 同一关系在正文与 related 里各写了一次
  • 提示:摘要过长之类的建议

这不是可选的装饰。 一个由人(或 agent)持续维护的知识库, 最容易的结局是慢慢烂掉——改了标题没改引用、删了页面留下断链。 机械的检查必须能进 CI,否则「知识库」会退化成「一堆文件」。

完整的规则表在 AGENTS.md——那份是写给 agent 看的,改规则时两边要一起改。

给 AI 读者那一份#

这一站有两个出口,服务两类读者:

Markdown 孪生文件。 每篇文章和知识页都有可直接访问的 .md URL。 在支持内容协商的部署平台上,请求页面 URL 时带上 Accept: text/markdown 也会得到 markdown;本站使用 GitHub Pages,因此应直接访问 .md 链接。 原理和托管限制见 内容协商。

目录与全文。 /llms.txt 是给 agent 看的目录(标题 + 一句话说明), /llms-full.txt 是全文内联版。每个页面还有 .md 孪生文件, 比如 /how-this-works.md。

需要说明的是:llms.txt 的实际效果被高估了—— Ahrefs 实测 13.7 万个域名里 97% 的 llms.txt 从未被请求过。 本站生成它是因为零成本,但主要依靠显式 .md 链接、内容清单和干净的 HTML。

部署#

静态产物,任何静态托管都能跑。但内容协商需要一层边缘函数—— 因为静态托管不解析请求头,它只会把文件原样吐出来。

项目里带了三个平台的现成实现,选你用的那个:

平台边缘函数平台配置
Cloudflare Pagesfunctions/[[path]].tspublic/_headers(会被拷进产物)
Netlifynetlify/edge-functions/negotiate.ts无额外配置
Vercelmiddleware.tsvercel.json

不想要这一层也没关系,站点照常工作,只是 agent 拿到的是 HTML 而不是 markdown。

详细说明#

这一页也有 markdown 版本:/letterpress/how-this-works.md
直接打开上面的 .md 链接即可读取;在支持内容协商的部署平台上, 也可以对页面 URL 发送 Accept: text/markdown。