Sätteri 与 unified:Markdown 处理的两条路线

Jun 23, 2026 · 1485 字

前几天看到一个消息,Astro 7 正式发布,默认换上了 Rust 写的 Sätteri 作为 Markdown 处理器。构建速度更快,插件更轻量,听起来一切都很美好。我的站点正好用 Astro,就顺手升级了。

结果 build 直接报错。原来是 Sätteri 不再内置 unified 的那套流水线,而我在 astro.config.ts 里配的 remark-math 和 rehype-katex 都是基于 unified 生态的插件,现在不兼容了。

我一开始还以为是配置问题,花了不少时间查文档。后来发现,Sätteri 的 AST 跟 MDAST 完全不是一回事,没有现成的 math 插件可以用。想继续用数学公式,要么自己写一个 Sätteri 插件,要么装回 @astrojs/markdown-remark 继续走 unified 的老路。

unified 的流水线

先说说 unified 是怎么工作的。Markdown 文本先进 remark-parse,出来的是一棵 MDAST 语法树。然后 remark 插件在这棵树上做变换,接着 remark-rehype 把树转成 HAST,rehype 插件继续改,最后 stringify 成 HTML。

这条流水线能跑通,全靠规范。MDAST 规定了 Markdown 节点长什么样,HAST 规定了 HTML 节点长什么样,unist 又给了共同的底层接口。三层规范叠在一起,插件之间才能互相协作。

remark-math 在 MDAST 阶段把 $...$ 识别成 math 节点,rehype-katex 在 HAST 阶段把这些节点转成 KaTeX 渲染后的 HTML。两个插件并不直接通信,但通过共享的 AST 规范间接配合。这种生态的丰富程度,是经过十年积累才有的——几百个插件,几乎你想得到的需求都有人做过。

但层数多了,AST 要被反复遍历。规范卡得太死,想做的事情如果不符合节点定义,就得绕路或者自定义类型。代价确实存在,只是以前没人太在意,因为生态太舒服了。

Sätteri 的扁平化

Sätteri 的做法完全不同。解析完 Markdown 直接得到一棵树,插件拿到树随便改。没有 MDAST,没有 HAST,没有 remark 和 rehype 的边界。

Rust 本身比 JavaScript 快一个数量级,省掉中间层的多次转换后,构建时间确实能缩不少。插件写起来也更直接,不需要 visitor 模式,拿到树,找到节点,改了就行。

我在 Astro 7 里第一次体验这种架构时,构建速度的提升是能感觉到的。但当我试图把 remark-math 和 rehype-katex 加回去的时候,问题就来了——Sätteri 不认识这些插件,因为它们操作的是 MDAST 和 HAST,不是 Sätteri 自己的 AST。

想继续用数学公式,理论上可以写一个 Sätteri 的 math 插件。但 Sätteri 的 AST 是它自己定的,没有社区共识。你写的插件,别的插件可能不认识。unified 里那种插件链上各自处理、最终拼出完整页面的模式,在这里很难复现。

也就是说,我不是在换一个更快的处理器,而是在换一个全新的、几乎没有插件的生态。这跟当年从 Webpack 切到 Vite 还不一样,Vite 至少兼容 Rollup 插件。Sätteri 这边,你基本得从零开始。

那我现在怎么办?

降级回 v6。

粤ICP备2025414119号 粤公网安备44030002006951号

© 2026 Saurlax · Powered by Astro