MdBin 升级:从自定义 Markdown 管道到 Streamdown
Source: Dev.to
旧的设置:它能工作,但
我最初的实现相当稳固。我使用 markdown-it-async 搭配 @shikijs/markdown-it 来进行语法高亮:
import { fromAsyncCodeToHtml } from '@shikijs/markdown-it/async'
import MarkdownItAsync from 'markdown-it-async'
import { codeToHtml } from 'shiki'
const md = MarkdownItAsync({
html: true,
xhtmlOut: true,
linkify: true,
typographer: true,
breaks: true,
})
md.use(
fromAsyncCodeToHtml(codeToHtml, {
themes: {
light: 'github-light',
dark: 'github-dark',
},
defaultColor: false,
cssVariablePrefix: '--shiki-',
})
)
export async function renderMarkdown(content: string): Promise {
const html = await md.renderAsync(content)
return html
}
然后在我的页面组件中,我使用经典的 dangerouslySetInnerHTML 渲染结果:
缺点
- 手动安全处理 —
dangerouslySetInnerHTML正如其名,使用时需格外小心。 - 缺乏内置控制 — 复制按钮、下载功能等都需要自己实现。
- Mermaid 成了噩梦 — 服务端渲染时往往不可靠。
- 包体积膨胀 — 每新增一种语言的高亮都会增加体积。
- 块级处理不完整 — 格式错误的 Markdown 可能导致整个渲染失败。
进入 Streamdown
当我发现 Streamdown 时,我最初把它否掉了。“它是用于 AI 流式传输的,”我想。“MdBin 渲染的是静态内容 SSR。”
但随后我仔细查看了功能集:
- 🎯 代码语法高亮,使用 Shiki(我已经在使用的)
- 📈 Mermaid 图表,真正支持 SSR
- 🛡️ 安全‑优先,配合
rehype-harden - 📊 GitHub 风格的 Markdown 开箱即用
- 🔢 数学渲染,通过 KaTeX
- ⚡ 内置控制,包括复制、下载、全屏
这正是一个 Markdown‑分享工具所需要的。
迁移:出乎意料的轻松
下面是新实现的样子:
import { Streamdown } from 'streamdown'
export default async function PastePage({ params }) {
const { id } = await params
const { decompressedContent, createdAt } = await cachedGetPaste(id)
return (
<Streamdown mode="static">
{decompressedContent}
</Streamdown>
)
}
就这么简单。没有单独的渲染函数,没有 dangerouslySetInnerHTML,也没有手动的安全清理。
Tailwind 的配置只需在 globals.css 中添加一行:
@source "../../node_modules/streamdown/dist/index.js";
为什么 v2.0.0 是游戏规则改变者
时机再好不过了。Streamdown 刚刚发布了 v2.0.0,带来了巨大的改进:
🚀 通过 CDN 将包体积降低 98 %
之前,打包所有 Shiki 语言语法和主题会让构建体积膨胀。现在,语言特定的高亮和 KaTeX CSS 会按需从 CDN 加载。你的构建保持精简,用户只会获取他们需要的资源。
📈 Mermaid SSR 终于可以用了
Markdown 中的 Mermaid 图表非常实用——流程图、时序图、架构文档——但 SSR 渲染一直有问题。现在它可以完美工作,并且采用基于视口的懒加载,防止在页面中出现多个图表时导致卡顿。
🛡️ 增强的安全性
rehype-harden + rehype-sanitize 意味着我不必担心恶意 Markdown 带来的 XSS 攻击。组件会自动处理消毒。
✨ 内置的用户体验优化
所有我本来得自己实现的控件?现在已内置:
- 代码块 – 复制按钮,语言指示
- 表格 – 下载为 CSV
- Mermaid – 下载为 PNG,复制 SVG,全屏查看并支持平移/缩放
我获得的
| 功能 | 之前 | 之后 |
|---|---|---|
| 安全 | 手动使用 dangerouslySetInnerHTML | 内置 rehype-harden |
| 代码复制 | 自定义 CopyButton 组件 | ✅ 内置 |
| Mermaid SSR | ❌ 损坏 | ✅ 可用 |
| 表格下载 | ❌ 未实现 | ✅ 内置 |
| 数学渲染 | ❌ 未实现 | ✅ 内置 KaTeX |
| 包大小 | 随着每种语言的增加而增长 | 按需 CDN 加载 |
| 不完整的 Markdown | 可能导致渲染错误 | 优雅处理 |
“流式”部分
你可能会好奇:“为什么要为静态内容使用流式优化的组件?”答案很简单——Streamdown 的流式模式提供了渐进式渲染。Markdown 会在解析后即时流向 DOM,这意味着:
- 更快的首次有内容绘制时间(尤其是对大型文章)。
- 在处理繁重的图表或代码块时,UI 仍保持响应。
- 对静态 SSR 和实时 AI 生成的流都同样适用,为未来功能提供灵活性。
简而言之,我获得了更简洁的代码库、更好的安全性、显著更小的包体积以及更丰富的用户体验——几乎无需迁移工作量。

“用于静态内容的 ed 库?”
公平的问题。mode="streaming" 和 isAnimating={false} 属性告诉 Streamdown 这是预渲染的内容——没有打字效果,也没有逐步显示。但其他所有好处仍然适用:
parseIncompleteMarkdown– 处理用户粘贴格式错误的 markdown(未闭合的代码块、不完整的表格)等边缘情况。它不会崩溃或显示乱码,而是优雅地渲染。- Memoized rendering – 即使没有流式处理,性能优化仍有助于重新渲染。
向 Vercel 团队致敬
The Streamdown team has done an incredible job packaging what could have been a complex, multi‑library setup into a single, well‑designed component. It powers their AI Elements Message component, but it’s genuinely useful for any markdown‑rendering use case.
- 文档很完善。
- 默认设置合理。
- 它就是能用。
试一试
前往 并粘贴一些 markdown。尝试:
- 代码块(任意语言)——注意复制按钮和语言徽章。
- Mermaid 图表——它们现在真的可以渲染!尝试全屏 + 平移/缩放。
- 表格——查看下载按钮。
- 数学公式——LaTeX 直接可用。
快速 Mermaid 示例,复制粘贴
graph TD
A[Paste Markdown] --> B[Streamdown Renders]
B --> C{What type?}
C -->|Code| D[Shiki Highlighting]
C -->|Diagram| E[Mermaid SVG]
C -->|Math| F[KaTeX Render]
D --> G[Beautiful Output]
E --> G
F --> G
- 进入全屏模式
- 退出全屏模式
接下来
随着渲染层现在由 Streamdown 负责,我可以专注于用户真正想要的功能:
- 过期选项 – 1 小时、1 天、1 周或永久。
- 密码保护 – 用于敏感内容。
- 编辑链接 – 在不创建新粘贴的情况下更新已有粘贴。
- 自定义主题 – 超越浅色/深色模式。
基础已经稳固。现在是构建的时候了。
TL;DR: 将 MdBin 从 markdown-it + Shiki 迁移到 Vercel 的 Streamdown。获得了内置代码复制、Mermaid 渲染(真正支持 SSR!)、数学支持、增强的安全性,以及体积缩小 98 % 的打包——全部来自一个组件。Vercel 团队这次表现堪称完美。
查看升级内容于 以及 Streamdown 仓库。