Vue 3 Markdown renderer optimized for large docs: progressive Mermaid, streaming diff code blocks, and fast real-time preview.
npm install markstream-vue> 针对 Vue 3 的高性能、流式友好型 Markdown 渲染组件 — 支持渐进式 Mermaid、流式 diff 代码块以及为大文档优化的实时预览。














需要其他框架/版本?
- Vue 2.6:请使用 markstream-vue2(基础移植版,功能更精简)
- React:请参考 packages/markstream-react 的说明 packages/markstream-react/README.md(初步移植版)
- 速览
- 立即试用
- 社区与支持
- 快速上手
- 常用命令
- 30 秒流式接入
- 性能模式
- 关键属性速览
- 适用场景
- 快问快答
- 为什么选择 markstream-vue
- Roadmap
- 发布
- 案例与展示
- 介绍视频
- 核心特性
- 贡献与社区
- 故障排查
- 鸣谢
- Star 历史
- 许可
> 📖 所有详细文档、API、示例和高级用法已迁移至 VitePress 中文文档站点:
> https://markstream-vue-docs.simonhe.me/zh/guide/
- 为 流式 Markdown(AI/聊天/SSE)打造,避免闪烁,内存可预期。
- 双渲染模式:长文档虚拟化窗口,或“打字机”式增量批次。
- 渐进式图表(Mermaid)与 流式代码块(Monaco/Shiki),跟上 diff/增量输出。
- 同时支持 Markdown 字符串或预解析节点,可在 Markdown 中嵌入 自定义 Vue 组件。
- TypeScript 优先,开箱默认即可上线(导入 CSS 即用)。
- Playground(交互演示): https://markstream-vue.simonhe.me/
- 交互测试页(可分享链接,便于复现): https://markstream-vue.simonhe.me/test
- 文档: https://markstream-vue-docs.simonhe.me/zh/guide/
- AI/LLM 项目索引(中文): https://markstream-vue-docs.simonhe.me/llms.zh-CN
- AI/LLM 项目索引(英文): https://markstream-vue-docs.simonhe.me/llms
- 一键 StackBlitz 体验: https://stackblitz.com/github/Simon-He95/markstream-vue?file=playground/src/App.vue
- 更新日志: CHANGELOG.md
- Nuxt playground:pnpm play:nuxt
- Discord: https://discord.gg/vkzdkjeRCW
- Discussions:https://github.com/Simon-He95/markstream-vue/discussions
- Discord:https://discord.gg/vkzdkjeRCW
- Issues:请使用模板并附上复现链接(https://markstream-vue.simonhe.me/test)
测试页内置编辑器 + 实时预览,并提供“生成分享链接”功能(过长内容会回退为直接打开或预填 GitHub Issue)。
``bash`
pnpm add markstream-vuenpm install markstream-vue
yarn add markstream-vue
`ts
import MarkdownRender from 'markstream-vue'
// main.ts
import { createApp } from 'vue'
import 'markstream-vue/index.css'
createApp({
components: { MarkdownRender },
template: '
setup() {
const doc = '# Hello markstream-vue\\n\\n支持 流式 节点。'
return { doc }
},
}).mount('#app')
`
确保在 CSS reset(如 @tailwind base 或 @unocss/reset)之后导入 markstream-vue/index.css,最好放在 @layer components 中以避免 Tailwind/UnoCSS 覆盖组件样式。根据需求再按需安装可选 peer 依赖:stream-monaco(Monaco 代码块)、shiki + stream-markdown(Shiki 高亮)、mermaid(Mermaid 图表)、katex(数学公式)。
渲染器的 CSS 会作用于内部 .markstream-vue 容器下,以尽量降低对全局的影响;如果你脱离 MarkdownRender 单独使用导出的节点组件,请在外层包一层带 markstream-vue 类名的容器。
暗色变量可以通过给祖先节点加 .dark,或直接给 MarkdownRender 传入 :is-dark="true"(仅对渲染器生效)。
按需启用重型依赖:
`ts
import { enableKatex, enableMermaid } from 'markstream-vue'
import 'markstream-vue/index.css'
import 'katex/dist/katex.min.css'
// 安装对应 peer 后再启用
enableMermaid()
enableKatex()
`
可选:CDN Worker(KaTeX / Mermaid)
如果你是用 CDN 引入 KaTeX,并且希望公式在 Web Worker 中渲染(不打包 / 不安装可选 peer),可以注入一个“CDN 加载 KaTeX”的 worker:
`ts
import { createKaTeXWorkerFromCDN, setKaTeXWorker } from 'markstream-vue'
const { worker } = createKaTeXWorkerFromCDN({
mode: 'classic',
// worker 内通过 importScripts() 加载的 UMD 构建
katexUrl: 'https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/katex.min.js',
mhchemUrl: 'https://cdn.jsdelivr.net/npm/katex@0.16.22/dist/contrib/mhchem.min.js',
})
if (worker)
setKaTeXWorker(worker)
`
如果你是用 CDN 引入 Mermaid,并且希望 Mermaid 的解析在 worker 中进行(用于渐进式 Mermaid 渲染的后台解析),可以注入 Mermaid parser worker:
`ts
import { createMermaidWorkerFromCDN, setMermaidWorker } from 'markstream-vue'
const { worker } = createMermaidWorkerFromCDN({
// Mermaid CDN 构建通常是 ESM,推荐 module worker。
mode: 'module',
workerOptions: { type: 'module' },
mermaidUrl: 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs',
})
if (worker)
setMermaidWorker(worker)
`
Nuxt 快速接入
`ts
// plugins/markstream-vue.client.ts
import { defineNuxtPlugin } from '#app'
import MarkdownRender from 'markstream-vue'
import 'markstream-vue/index.css'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component('MarkdownRender', MarkdownRender)
})
`
然后在页面中直接使用 。
- pnpm dev — playground 开发pnpm play:nuxt
- — Nuxt playground 开发pnpm build
- — 构建库与 CSSpnpm test
- — Vitest 测试(快照用 pnpm test:update)pnpm typecheck
- / pnpm lint — 类型检查与 Lint
用 SSE / WebSocket 增量渲染 Markdown:
`ts
import type { ParsedNode } from 'markstream-vue'
import MarkdownRender, { getMarkdown, parseMarkdownToStructure } from 'markstream-vue'
import { ref } from 'vue'
const nodes = ref
const buffer = ref('')
const md = getMarkdown()
function addChunk(chunk: string) {
buffer.value += chunk
nodes.value = parseMarkdownToStructure(buffer.value, md)
}
// 例如在 SSE / onmessage 处理器中
eventSource.onmessage = event => addChunk(event.data)
// template
//
// :max-live-nodes="0"
// :batch-rendering="{
// renderBatchSize: 16,
// renderBatchDelay: 8,
// }"
// />
`
按页面需要切换渲染风格:
- 虚拟化窗口(默认):长文档滚动平稳、内存稳定。
- 增量批次:将 :max-live-nodes="0",获得更明显的“打字机”体验与轻量占位。
进阶:SSR / Worker / 流式续写
在服务端或 Worker 预解析 Markdown,前端直接渲染节点:
`ts
// server or worker
import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue'
const md = getMarkdown()
const nodes = parseMarkdownToStructure('# Hello\n\n服务端解析一次', md)
// 将 nodes JSON 下发到客户端
`
`vue`
这样可以避免前端解析,保持 SSR/水合的一致性。
- 服务端:解析首批 Markdown,序列化 initialNodes(以及 initialMarkdown,便于后续流式追加)。
- 客户端:用相同的解析配置水合,然后继续流式追加:
`ts
import type { ParsedNode } from 'markstream-vue'
import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue'
import { ref } from 'vue'
const nodes = ref
const buffer = ref(initialMarkdown)
const md = getMarkdown() // 与服务端保持一致
function addChunk(chunk: string) {
buffer.value += chunk
nodes.value = parseMarkdownToStructure(buffer.value, md)
}
`
这样无需重新解析 SSR 内容,同时还能通过 SSE/WebSocket 持续追加后续片段。
> 提示:当你明确知道流已结束(消息已完整)时,建议用 parseMarkdownToStructure(buffer.value, md, { final: true }) 或在组件上设置 :final="true",以关闭解析器的中间态(loading)策略,避免末尾残留分隔符(如 $$、未闭合 code fence)导致永久 loading。
- 默认虚拟化窗口:保持 max-live-nodes 默认值(320),渲染器会立即渲染当前窗口的节点,同时只保留有限数量的 DOM 节点,实现平滑滚动与可控内存,占位骨架极少。:max-live-nodes="0"
- 增量流式模式:当需要更明显的“打字机”体验时,将 。这会关闭虚拟化并启用 batchRendering 系列参数控制的增量渲染,新的节点会以小批次加上占位骨架的形式进入视图。
可根据页面类型选择最合适的模式:虚拟化适合长文档/回溯需求,增量流式适合聊天或 AI 输出面板。
> 小贴士:聊天场景可使用 max-live-nodes="0",并将 renderBatchSize 调小(如 16),renderBatchDelay 设为较小值(如 8ms),获得平滑的“打字”节奏且避免大段跳变。如需限制单帧 CPU,可适当调低 renderBatchBudgetMs。
- content 与 nodes:传原始 Markdown 或预解析节点(来自 parseMarkdownToStructure)。max-live-nodes
- :320(默认虚拟化)或 0(增量批次)。batchRendering
- :用 initialRenderBatchSize、renderBatchSize、renderBatchDelay、renderBatchBudgetMs 微调批次。enableMermaid
- / enableKatex:用于(重新)启用重型依赖或自定义 loader(可与 disableMermaid / disableKatex 配合)。parse-options
- :在组件上复用解析钩子(如 preTransformTokens、requireClosingStrong)。final
- :标记“最终态/流结束”,关闭中间态 loading 解析并强制收敛未闭合结构。custom-html-tags
- :扩展流式 HTML 白名单并将这些标签输出为自定义节点,便于 setCustomComponents 直接映射(如 ['thinking'])。setCustomComponents(customId?, mapping)
- :为自定义标签/标记注册内嵌 Vue 组件(传 custom-id 可限定作用域)。
示例:将 Markdown 占位符映射到 Vue 组件(作用域)
`ts
import { setCustomComponents } from 'markstream-vue'
setCustomComponents('docs', {
CALLOUT: () => import('./components/Callout.vue'),
})
// Markdown: [[CALLOUT:warning title="提示" body="具体内容"]]
`
渲染时使用同一个 custom-id:
`vue`
custom-id="docs"
/>
解析钩子示例(服务端/客户端保持一致):
`vue`
:parse-options="{
requireClosingStrong: true,
preTransformTokens: (tokens) => tokens,
}"
/>
- AI / 聊天界面:Markdown token 通过 SSE/WebSocket 持续抵达,要求无闪烁与稳定内存。
- 文档、变更日志、知识库:需要即时加载,同时保持长内容滚动的流畅性。
- 流式 diff / 代码审查:Monaco 增量更新让大代码块也能跟上变更。
- 图表与示意:Mermaid 渐进式渲染,避免阻塞主渲染。
- Markdown 驱动的界面中嵌入 Vue 组件(callout、交互式挂件、CTA 等)。
- Mermaid / KaTeX 不显示?安装对应 peer(mermaid / katex),并传入 :enable-mermaid="true" / :enable-katex="true" 或调用 loader 设置函数。如果你是用 CDN