跳转到内容
Akatshi's Blog
返回

如何写一篇博文:文件结构、Frontmatter 与排版指南

这篇指南写给所有想在这个博客框架上发文章的人——包括未来的我自己。

本站基于 Astro + AstroPaper 主题搭建,文章的编写方式非常简单:本质上你只需要新建一个 .md 或 .mdx 文本文件,填写一段 YAML 格式的「frontmatter」作为元信息,然后用 Markdown 写正文。剩下的排版、目录、搜索索引、分享卡片,都由框架自动处理。

下面从「文章放哪里」开始,一步步讲清楚。

Table of contents

Open Table of contents

文章放在哪里

所有文章都存放在 src/content/posts/ 目录下。本站的约定是:一篇文章 = 一个文件夹,正文固定叫 index.mdx,配图放在同目录的 assets/ 里随文章一起走:

src/content/posts/
├── _20260909-1/   ← 文件夹 = 发布时间(当天第一篇,序号 1)
│   └── index.mdx
├── _20260909-2/
│   ├── index.mdx   ← 正文(.mdx 或 .md 均可)
│   └── assets/     ← 这篇的配图(没图可以省略)
└── _20260909-3/
    ├── index.mdx
    └── assets/
        ├── IVF1.png
        └── HNSW.png
Tip

为什么文件夹要 _ 开头?_ 开头的目录里的文件照常发布,但目录名不会进入链接;_ 开头的文件则完全不会发布(适合随手放草稿)。所以链接永远只由 slug 决定,不会混进文件夹名。想让文章彻底不发布,把它移出 posts 集合(比如放进 src/content/archive/),或者加 draft: true。

文章链接由什么决定

文章的 URL 完全由 frontmatter 里的 slug 字段决定,与文件路径、文件名无关:

Frontmatter:文章的「身份证」

Frontmatter 是文件最顶部用 --- 包裹的一段 YAML,存放文章的所有元信息。它会被用于列表卡片、SEO、分享卡片、RSS 等几乎所有需要展示文章信息的地方。

以下是本站支持的全部字段:

字段说明备注
title文章标题,同时作为页面 h1必填
slug文章链接标识,即 URL 中 /posts/ 后面的一段必填
description文章摘要,用于列表卡片和 SEO 描述必填
pubDatetime发布时间,ISO 8601 格式必填
modDatetime修改时间,ISO 8601 格式,只有文章被修改过才加可选
author作者名默认取站点配置的作者(Akatshi)
featured是否在首页「精选」区域展示默认 false
draft是否为草稿(草稿不会出现在任何页面)默认 false
tags标签列表,YAML 数组格式默认 others
ogImage社交分享卡片图,可以是远程 URL 或相对路径可选;不填则自动生成
canonicalURL规范链接,若文章已发布在其他地方用可选
hideEditPost隐藏这篇文章标题下方的「编辑本文」按钮可选,默认 false
timezone仅对本文生效的时区(IANA 格式),覆盖站点全局时区可选,默认 Asia/Shanghai

其中 title、slug、description、pubDatetime 四项是必填的。title、slug 和 description 对 SEO 和卡片展示很重要,请务必认真填写,不要偷懒。

Tip

如何快速拿到 ISO 8601 时间?在浏览器控制台运行 new Date().toISOString(),或者直接执行 date -u +%Y-%m-%dT%H:%M:%SZ。

一个标准的 frontmatter 示例

---
title: 文章的中文标题
slug: 20260909-4 # 默认是日期码;发布前想换成更好记的词也随时可以(中英文都支持)
author: Akatshi # 不填则默认是站点作者
pubDatetime: 2026-09-09T10:30:00+08:00
modDatetime: 2026-09-10T21:00:00+08:00 # 修改过文章再补上
featured: false
draft: true # 草稿阶段写 true,发布前改成 false
tags:
  - guide
  - blog
description: 一句话说清这篇文章讲什么,会出现在列表卡片和搜索引擎摘要里。
---src/content/posts/_20260909-4/index.mdx
关于发布时间的一些细节
  • 填未来的时间,文章会被视为「定时发布」:到点之前读者看不到,只有你可以通过本地开发模式预览
  • 列表排序按 modDatetime(若有)否则 pubDatetime 倒序,所以改完文章记得更新 modDatetime,否则它会被挤到列表下方

正文的排版语法

正文就是 Markdown。这里列几个本站写作时最常用的要点,也相当于一个快速备忘录。

标题层级:h1 留给 title

页面的大标题(h1)已经由 frontmatter 的 title 输出了,所以正文里的章节标题请从 ##(h2)开始,最多用到 ######(h6)。这既是视觉规范,也有利于 SEO 和阅读器无障碍体验。

## 二级标题:章节

### 三级标题:小节

常用行内与段落语法

**加粗**、*斜体*、~~删除线~~、`行内代码`、[超链接](https://example.com)

- 无序列表项
- 无序列表项

1. 有序列表项
2. 有序列表项

> 引用别人的话,或强调一段观点。

---

用一条分隔线把两个大段落隔开,也是不错的结构手法。

代码块与语法高亮

代码块用三个反引号包裹并标注语言,本站使用 Shiki 做高亮,支持文件标题、增删标记、关键词高亮等增强语法。这也是写作技术类文章最常用的功能:

function greet(name: string) {
  return `Hello, ${name}!`;
}

const message = greet("世界"); 
const oldMessage = "你好";examples/hello.ts

上面这段代码块本身就用到了三种标记:// [!code ++] 绿色新增行、// [!code --] 红色删除行、// [!code highlight] 高亮当前行。在代码块第一行反引号后写 file="路径/文件名.ts" 即可显示文件标题栏。

Callout:带图标的提示块

想在正文中插入醒目的提示、警告或小贴士?本站支持 Obsidian 风格的 callout,写法是「blockquote + 类型标记」,正文中渲染为带图标和底色的小卡片:

Note

补充性说明,读者应该留意但不必紧张。

Tip

实用的建议、快捷键或最佳实践。

Important

需要特别强调的关键信息。

Warning

可能出错或有副作用的事情。

Danger

有严重风险,可能导致数据丢失或行为错误。

语法来源也很直观:

> [!TIP]
> 提示内容写在这一行。

还可以自定义标题、或者做成可折叠的:

自定义标题

类型标记后面跟的文字会变成卡片标题。不写的话默认用类型名。

默认折叠的警告

加上 - 之后默认收起,读者点开才看得到,适合放很长但不打断阅读的补充说明。

> [!NOTE] 自定义标题
> 类型后跟的文字即标题。

> [!WARNING]- 默认折叠
> `-` 表示默认收起,`+` 表示默认展开但可收起。
Tip

本站支持的 callout 类型还包括 ABSTRACT、INFO、TODO、SUCCESS、QUESTION、FAILURE、BUG、EXAMPLE、QUOTE 等,每种都有对应图标与颜色。一般记住上面五种就够用了。

插入目录

默认情况下文章不会自动生成目录。想加目录,就在想让目录出现的位置写一行固定的二级标题:

## 开头的内容

## Table of contents

## 正文第一个章节

注意 ## Table of contents 这行必须一字不差用英文写(它是处理管线的触发词)。构建后它会变成一个可展开的「目录」列表,自动收集你正文中后面的标题。目录适合长文,短文不写也没关系。

图片怎么放

图片有三种存放方式,取舍在于「要不要自动优化」以及「要不要跟文章放一起」:

方式一:放在文章自己的 assets/(推荐)

配合前面「一篇一文件夹」的约定,配图放进正文旁的 assets/ 子目录,在 .mdx 正文里用相对路径直接引用。构建时 Astro 会把它们当作可优化资源自动处理(压缩、加 hash、适配格式),这是本站文章配图最常用的方式:

src/content/posts/_20260909-3/
├── index.mdx
└── assets/
    ├── IVF1.png
    └── HNSW.png
![IVF 聚类示意图(替代文字,方便无障碍阅读,也有利于 SEO)](assets/IVF1.png)

相对路径以 index.mdx 所在目录为基准,所以 assets/IVF1.png 就能指到上面的图。图随文走,删文章时整个文件夹一起删,不会留孤儿图片——每篇都带图的场景强烈推荐这种。

方式二:放在 src/assets/(多篇文章复用,自动优化)

适合多篇共用或用于站点公共位置的图片。放进 src/assets/ 后,在 .mdx 里通过 @/assets 别名导入,用 <Image> 组件渲染,Astro 会做压缩、尺寸适配和格式转换:

import { Image } from "astro:assets";
import exampleImg from "@/assets/images/example.jpg";

<Image src={exampleImg} alt="一张经过优化的图片" />

方式三:放在 public/(不优化,仅简单直接)

把图片丢进 public/images/,用绝对路径引用即可。Astro 不会做任何处理,原样输出,适合已经压好、偶尔一用的图:

![替代文字,方便无障碍阅读,也有利于 SEO](/images/某个图.jpg)
Warning

无论哪种方式,上传前都建议先用 TinyPNG 之类的工具压缩一遍。尤其是 public/ 目录里的图片,未经优化会明显拖慢页面。正文配图请克制,少而精。

草稿与预览流程

写作时最舒服的工作流是这样的:

  1. 复制一个已有 post 或按上面的 frontmatter 模板新建文件,先把 draft: true 写上
  2. 运行 pnpm dev,在 http://localhost:4321 实时预览——开发模式下草稿和未到发布时间的定时文章对你都是可见的,方便边写边检查排版
  3. 写完检查无误后,把 draft 改成 false(或删掉),提交推送
pnpm new post # 生成新文章骨架(按当天日期 + 顺序码命名,draft: true)
pnpm dev     # 本地开发预览
pnpm sync    # 改动内容 schema 后重新生成类型
pnpm build   # 类型检查 + 构建 + 生成 Pagefind 搜索索引
pnpm preview # 本地预览生产构建
Warning

站点搜索依赖 Pagefind 索引,而它是在 pnpm build 阶段生成的。所以部署前请务必执行一次 pnpm build,否则新文章搜不到。

一篇完整文章的模板

步骤:新建一篇

  1. 运行 pnpm new post(想顺便带标题可以写成 pnpm new post "文章标题"),脚本按当前日期自动接力生成骨架:
src/content/posts/
├── _20260909-1/   ← 当天第一篇是 1
├── _20260909-2/
├── _20260909-3/
└── _20260909-4/   ← 新创建的会接着排 4、5、6…,不用手动数
    ├── index.mdx  ← 含草稿模板,frontmatter 已自动填好时间与 slug
    └── assets/    ← 空的,配图放这里
  1. pnpm new post 已把 slug 默认填成 20260909-4 这种日期码(URL:/posts/20260909-4),直接发布也可以;想更好记就发布前替换成短词,中英文都行(中文 slug 本站已验证可用):
slug: 向量数据库索引   # -> /posts/向量数据库索引
# 或
slug: rag-retrieval     # -> /posts/rag-retrieval
  1. 写正文;配图放进 assets/,按上面「方式一」用 ![](assets/图片.png) 引用
  2. 写完预览无误后,把 draft 改成 false 即可发布

下面是一份参考模板(pnpm new post 生成的文件结构与此相同):

---
title: 这里是文章标题
slug: 20260909-4 # 自动生成;发布前想换成易记的词也行,中英文都支持
description: 一句话摘要,会显示在列表卡片和搜索结果里。
pubDatetime: 2026-09-09T10:30:00+08:00
featured: false
draft: true # 写完后改成 false
tags:
  - guide
  - blog
---

开场白:用两三句话说清楚这篇文章要解决什么问题,给读者一个继续读下去的理由。

## Table of contents

## 第一个小节

正文内容。段落之间用空行隔开,一段只讲一件事。

### 如果需要,可以再分小标题

> [!TIP]
> 关键经验用 callout 强调,比大段加粗文字更好读。

## 结尾

用一两句话总结全文,并给出下一步行动建议。如果参考了他人的文章或项目,记得在这里附上链接致谢。

写作的几条朴素建议

最后分享几条我自己的写作习惯,供参考:

写完这篇文章本身,就是一次很好的实践——你现在看到的所有排版元素(目录、callout、代码高亮、表格),都来自上面的语法。如果还有哪里不清楚,翻一翻 src/content/posts/ 里其他示例文章的源码,是最好的参考。


分享这篇文章:

下一篇
文本生成里的采样参数三件套:top-k、top-p 和 temperature