如果眼睛足够敏锐,你会发现有些 AI tool 通过 SSE 返回流式文本时,会先打印出 *
**
-
或其它 Markdown 格式化字符,之后又迅速消失。用户阅读过程中,格式化的不同导致不同程度的 layout shift,文本不停换位置或忽大忽小,造成视觉疲劳。
问题
在网页中,我们通常用 react-markdown 来解析 Markdown 代码,一次性整体解析是没问题的,但 SSE 零零散散地把字串返到页面 Markdown 未成功解析时,用户就会看到奇奇怪怪的字符先。
解决办法
- 写正则,修正各种 Markdown 语法不正确的场景;
- 直接用 package Streamdown
代码
js
// Nextjs
'use client';
import { useChat } from '@ai-sdk/react';
import { useState } from 'react';
import { Streamdown } from 'streamdown'; // 引入 streamdown
export default function Page() {
const { messages, sendMessage, status } = useChat();
const [input, setInput] = useState('');
return (
<>
{messages.map(message => (
<div key={message.id}>
{message.parts.filter(part => part.type === 'text').map((part, index) => (
{ /* 用 Streamdown 包住 Markdown 文本 */ }
<Streamdown key={index}>{part.text}</Streamdown>
))}
</div>
))}
<form
onSubmit={e => {
e.preventDefault();
if (input.trim()) {
sendMessage({ text: input });
setInput('');
}
}}
>
<input
value={input}
onChange={e => setInput(e.target.value)}
disabled={status !== 'ready'}
placeholder="说点什么..."
/>
<button type="submit" disabled={status !== 'ready'}>
提交
</button>
</form>
</>
);
}
解决的痛点
内置的排版样式
Streamdown 为常见的 Markdown 提供了内置的 Tailwind 类,自动格式化标题、列表、代码块等。

GitHub 风格的 Markdown
Streamdown 默认支持 GitHub 风格的 Markdown (GFM),可以正常解析任务列表、表格等。

美观、交互式的代码区块
Streamdown 使用 Shiki 来高亮显示代码块,自带复制按钮,悬停显示复制按钮!

数学表达式
Streamdown 通过 remark-math 和 KaTeX 支持 LaTeX 数学表达式,在 Markdown 中完美展现各种数学符号。韦神满意地笑了!

提前解析未闭合的 Markdown 标签
Streamdown 提前解析未闭合的 Markdown 标签(#
标题、内联代码
、**粗体**
、_斜体_
、[链接]()
等),极大提升了用户体验,大大减少了文本来回抖动的现象。

内置安全机制
Streamdown 检测 Markdown 中不安全的元素,自动屏蔽可能已 被 prompt 注入攻击 的图像和链接。

演示仓库
以上都为静态图片,未能动态演示出打字过程中的变化,checkout Demo of Streamdown 到本地试下。Have fun :)