Markdown 渲染管线设计:从 MDX 到 HTML 的完整链路

技术架构(更新于 2026年5月29日)

Markdown 渲染的挑战

工具库的博客和教程系统需要将 MDX/Markdown 文件渲染为安全的 HTML。看似简单,实际涉及:

  • 语法扩展:GFM 表格、任务列表、删除线
  • 安全消毒:防止 XSS(用户不可信内容)
  • 代码高亮:语法着色的 <pre><code>
  • 标题锚点:自动生成 slug 用于目录跳转
  • 内部链接/pdf/merge 转为带 locale 前缀的链接

unified 生态管线

MDX/Markdown 原文
     ↓ remark-parse        (Markdown → MDAST)
     ↓ remark-gfm          (GFM 扩展)
     ↓ remark-rehype        (MDAST → HAST)
     ↓ rehype-slug          (标题添加 id)
     ↓ rehype-stringify     (HAST → HTML)
HTML 输出

工具库在 src/lib/blog/render-mdx.ts 中实现了这条管线:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkGfm from 'remark-gfm';
import remarkRehype from 'remark-rehype';
import rehypeSlug from 'rehype-slug';
import rehypeStringify from 'rehype-stringify';

const processor = unified()
  .use(remarkParse)
  .use(remarkGfm)
  .use(remarkRehype, { allowDangerousHtml: false })
  .use(rehypeSlug)
  .use(rehypeStringify);

Frontmatter 解析

每篇文章的元数据通过 gray-matter 从 MDX 头部提取:

---
title: "文章标题"
description: "SEO 描述"
author: "老张(工具库站长)"
---

正文内容...
import matter from 'gray-matter';

const { data: frontmatter, content } = matter(rawMdx);
// frontmatter.title → "文章标题"
// content → 正文 Markdown

Frontmatter 用于 SEO metadata、Open Graph 标签和 JSON-LD 结构化数据。


安全考虑

禁止原始 HTML 注入

.use(remarkRehype, { allowDangerousHtml: false })

设置为 false 时,Markdown 中的 <script> 标签会被转义为文本,而非执行。

链接安全

外部链接应添加 rel="noopener noreferrer"target="_blank"

// rehype 插件:为外部链接添加安全属性
function rehypeExternalLinks() {
  return (tree) => {
    visit(tree, 'element', (node) => {
      if (node.tagName === 'a' && isExternal(node.properties.href)) {
        node.properties.target = '_blank';
        node.properties.rel = 'noopener noreferrer';
      }
    });
  };
}

多语言内容管理

工具库的内容文件组织:

src/content/blog/my-article/
  ├── meta.json          ← 共享元数据(分类、标签、日期)
  ├── zh-CN.mdx          ← 简体中文正文
  ├── zh-TW.mdx          ← 繁体中文正文
  ├── en.mdx             ← 英文正文
  └── ja.mdx             ← 日文正文

meta.json 存储语言无关的数据,*.mdx 存储各语言的正文和 frontmatter。构建时 generateStaticParams 枚举所有 slug × locale 组合预渲染。


性能优化

构建时渲染 vs 运行时渲染

工具库选择构建时渲染(SSG):

next build → 读取 MDX → unified 处理 → HTML 写入 out/
运行时 → 直接返回静态 HTML(零处理开销)

对比运行时渲染(每次请求都处理 Markdown),SSG 的 TTFB 从 ~200ms 降至 ~50ms。

增量内容更新

新增或修改文章后需要重新 next build。对于 18+ 篇文章 × 4 语言 = 72 个页面,完整构建约 3-5 分钟。


与 MDX 组件的关系

当前工具库使用纯 Markdown(非 React 组件 MDX),优点是:

  • 渲染管线简单,无 React SSR 开销
  • 内容文件可被任何 Markdown 编辑器编辑
  • 翻译工作只需处理纯文本

未来如需在文章中嵌入交互组件(如 live demo),可升级到 @next/mdx + React 组件。


总结

Markdown 渲染管线是内容驱动网站的核心基础设施。remark/rehype 生态提供了可组合的处理器链,gray-matter 处理元数据,构建时渲染确保极致性能。工具库的博客系统正是这套架构的实战应用。

本站提供浏览器本地工具,免注册即可试用 →

#Markdown#MDX#remark#rehype#内容渲染