用 MDX 写文章:在 Markdown 里塞进组件

演示这个博客的 MDX 能力:KaTeX 公式、任务列表、脚注、表格、代码高亮、以及怎么在正文里插入自定义组件。

用 MDX 写文章:在 Markdown 里塞进组件

Markdown 写久了会碰到天花板:想插一个对比卡片、一个可交互的 demo,就只能写裸 HTML。MDX 解决的正是这件事 —— 它是 Markdown 的超集,可以随时变成组件。

数学公式

行内公式用两个美元符号,比如缓存命中率的定义 h=NhitNtotalh = \frac{N_{hit}}{N_{total}},或者时间复杂度 O(nlog⁡n)O(n \log n)。

块级公式单独一段:

Tp99=μ+z0.99⋅σ≈μ+2.326 σT_{p99} = \mu + z_{0.99} \cdot \sigma \approx \mu + 2.326\,\sigma

Latency 的分布通常不是正态的,所以更常用的是分位数:

P(X≤xp)=p,p∈{0.5,0.9,0.99}P(X \le x_p) = p, \quad p \in \{0.5, 0.9, 0.99\}

任务列表

  • 支持 GFM 表格与任务列表
  • 代码高亮(亮/暗双主题)
  • KaTeX 数学公式
  • Callout 提示块
  • 图表(mermaid)渲染
  • 交互式代码演示

表格与对齐

指标p50p95p99说明
边缘函数冷启动0 ms0 ms1 msWorkers 无冷启动
KV 读取3 ms8 ms22 ms同区域
KV 读取(跨区)40 ms90 ms180 ms缓存未命中
静态资源命中 CDN12 ms35 ms80 ms视网络而定

脚注

Pages Functions 的计费单位是请求数1,KV 的计费单位是读写次数2。对一个个人博客来说,这两个数字都很难碰到天花板。

引用与嵌套

好的设计是尽可能少的设计。

—— Dieter Rams

嵌套引用也支持,但不建议用超过两层。读者会在第三层迷路。

行内标记

可以用 行内代码、加粗、斜体、删除线、链接,以及键盘按键 ⌘ + K 这种写法(这里用了裸 HTML,MDX 完全允许)。

长代码块

---
export const getStaticPaths = (async () => {
	const posts = await getPosts();
	return posts.map((post) => ({
		params: { slug: postSlug(post) },
		props: { post, all: posts.map(toMeta) },
	}));
}) satisfies GetStaticPaths;

const { post, all } = Astro.props;
const meta = toMeta(post);
const { Content } = await render(post);
---
- const posts = await getCollection('blog');
+ const posts = await getCollection('blog', ({ data }) => !data.draft);

在正文里放组件(MDX 专属)

这是 MDX 最有价值的部分。.mdx 文件里可以直接 import 并渲染 Astro 组件:

import Callout from '@/components/Callout.astro';

<Callout kind="tip" title="注意">
  这里是一个真正的组件,不是 Markdown 语法糖。
</Callout>

因为组件在构建期渲染,所以产物依然是纯 HTML —— 零客户端 JS。

小结

写作体验的优先级其实很朴素:

  1. 打开文件就能写,不需要心理建设
  2. 需要什么能力,当场就能用上(而不是「等我有空重构博客再加」)
  3. 写完 git push,剩下的交给 CI

MDX 加上 Astro 的构建期渲染,刚好满足这三条。

Footnotes

  1. 免费额度是每天 100,000 次请求,超过后按每百万次 $0.30 计费。 ↩

  2. KV 免费额度是每天 100,000 次读、1,000 次写。写操作额度小得多,但浏览量场景下完全够用。 ↩

评论区还没开张 —— 想开启的话,把 src/data/site.ts 里FEATURES.comments 的 enabled 设为 true 并填入 giscus 配置即可。

也许你还想看