# Markstream
> 面向 AI 应用的多框架流式 Markdown 渲染器家族 — 支持 Vue、React、Svelte、Angular、Nuxt 和 Next.js。
Markstream 专为在用户眼前持续变化的 Markdown 场景而构建:LLM token 流、SSE/WebSocket 输出、AI 聊天消息、未闭合 Markdown 中间态、长文档、渐进式 Mermaid 图表、KaTeX 数学公式、流式代码块以及安全的组件化渲染。
Vue 3、Nuxt 和 VitePress 项目优先使用 `markstream-vue`;React、Svelte、Angular、Vue 2 项目使用对应 sibling package。普通 AI 聊天可以直接传不断累积的 `content` 字符串,只有外层已经负责解析、batch 或 worker AST 时才需要 `nodes` 路径。
[](README.md)
[](https://markstream.simonhe.me/zh/guide)
[](https://markstream-vue.simonhe.me/)
[](https://markstream-vue.simonhe.me/test)
Vue 包:
[](https://www.npmjs.com/package/markstream-vue)
[](https://www.npmjs.com/package/markstream-vue)
[](https://bundlephobia.com/package/markstream-vue)
其它框架包:
[](https://www.npmjs.com/package/markstream-react)
[](https://www.npmjs.com/package/markstream-svelte)
[](https://www.npmjs.com/package/markstream-angular)
[](https://www.npmjs.com/package/markstream-vue2)
[](https://github.com/Simon-He95/markstream-vue/releases)
[](https://github.com/Simon-He95/markstream-vue/discussions)
[](https://discord.gg/vkzdkjeRCW)
[](./SUPPORT.md)
[](./SECURITY.md)
[](https://github.com/Simon-He95/markstream-vue/actions/workflows/ci.yml)
[](./license)
## 包矩阵
如果你还在选择框架包,先看 [框架总览](https://markstream.simonhe.me/zh/frameworks)。
| 包 | 框架 | 安装 | 文档 |
| --- | --- | --- | --- |
| `markstream-vue` | Vue 3 / Nuxt / VitePress | `pnpm add markstream-vue` | [框架总览](https://markstream.simonhe.me/zh/frameworks) · [Vue 指南](https://markstream.simonhe.me/zh/frameworks/vue) · [Nuxt 指南](https://markstream.simonhe.me/zh/frameworks/nuxt) |
| `markstream-react` | React / Next.js / Remix | `pnpm add markstream-react` | [React 指南](https://markstream.simonhe.me/zh/frameworks/react) · [Next.js 指南](https://markstream.simonhe.me/zh/frameworks/next) |
| `markstream-svelte` | Svelte 5 | `pnpm add markstream-svelte svelte@^5` | [Svelte 指南](https://markstream.simonhe.me/zh/frameworks/svelte) |
| `markstream-angular` | Angular standalone | `pnpm add markstream-angular` | [Angular 指南](https://markstream.simonhe.me/zh/frameworks/angular) |
| `markstream-vue2` | Vue 2.6 / 2.7 | `pnpm add markstream-vue2` | [Vue 2 指南](https://markstream.simonhe.me/zh/frameworks/vue2) · [快速开始](https://markstream.simonhe.me/zh/guide/vue2-quick-start) |
| `stream-markdown-parser` | 任意 JS/TS 应用 | `pnpm add stream-markdown-parser` | [解析器指南](https://markstream.simonhe.me/zh/guide/parser-api) |
| `markstream-core` | 框架无关 | `pnpm add markstream-core` | [Core 包](./packages/markstream-core/README.md) |
### 我该用哪个包?
- **Vue 3 / Nuxt / VitePress** → `markstream-vue`
- **React / Next.js / Remix** → `markstream-react`
- **Svelte 5** → `markstream-svelte`
- **Angular standalone** → `markstream-angular`
- **Vue 2.6 / 2.7** → `markstream-vue2`
- **仅需框架无关的解析** → `stream-markdown-parser`
- **流式控制器工具** → `markstream-core`
## 稳定性
`markstream-vue@1.0` 是最成熟的渲染器,稳定面包括:`MarkdownRender`、流式内容渲染、预解析节点渲染、安全 HTML 策略、可选 Mermaid / KaTeX / Monaco / D2 / Infographic 集成、虚拟滚动协调、CSS 导出、worker client 子路径以及 Vite / Nuxt / VitePress 的 SSR 导入。
跨框架渲染器(`markstream-react`、`markstream-svelte`、`markstream-angular`、`markstream-vue2`)已可用并积极开发中。请查看各包文档了解 API 成熟度、框架支持和已知限制。
- [速览](#速览)
- [按场景选择入口](#按场景选择入口)
- [立即试用](#-立即试用)
- [社区与支持](#-社区与支持)
- [快速上手](#-快速上手)
- [常用命令](#-常用命令)
- [30 秒流式接入](#-30-秒流式接入)
- [性能模式](#-性能模式)
- [关键属性速览](#-关键属性速览)
- [适用场景](#-适用场景)
- [快问快答](#-快问快答)
- [为什么选择 markstream-vue](#-为什么选择-markstream-vue而不是普通-markdown-渲染器)
- [Roadmap](#-roadmap快照)
- [发布](#-发布)
- [案例与展示](#-案例与展示)
- [介绍视频](#介绍视频)
- [核心特性](#核心特性)
- [贡献与社区](#-贡献与社区)
- [故障排查](#故障排查--常见问题)
- [鸣谢](#鸣谢)
- [Star 历史](#star-历史)
- [许可](#许可)
> 📖 框架总览、详细文档、API、示例和高级用法:
> https://markstream.simonhe.me/frameworks
## 速览
- 为 **流式 Markdown**(AI/聊天/SSE)打造,目标是减少闪烁并保持内存可预期。
- **双渲染模式**:长文档虚拟化窗口,或“打字机”式增量批次。
- **渐进式图表**(Mermaid)与 **流式代码块**(Monaco/Shiki),跟上 diff/增量输出。
- 同时支持 **Markdown 字符串或预解析节点**,可在 Vue、React、Svelte 和 Angular 中嵌入 **自定义框架组件**。
- TypeScript 优先,开箱默认即可上线(导入 CSS 即用)。
## 按场景选择入口
| 如果你现在想做的是... | 先看这里 | 然后看 |
| --- | --- | --- |
| 先把第一段渲染跑起来 | [框架总览](https://markstream.simonhe.me/zh/frameworks) | [快速上手](#-快速上手) |
| 接到文档站或 VitePress 主题里 | [文档站与 VitePress 集成](https://markstream.simonhe.me/zh/guide/vitepress-docs-integration) | [自定义标签与高级组件](https://markstream.simonhe.me/zh/guide/custom-components) |
| 做 AI 聊天界面或 SSE 流式输出 | [AI 聊天与流式输出](https://markstream.simonhe.me/zh/guide/ai-chat-streaming) | [性能](https://markstream.simonhe.me/zh/guide/performance) |
| 替换一个内置节点渲染器 | [覆盖内置组件](https://markstream.simonhe.me/zh/guide/component-overrides) | [渲染器与节点组件](https://markstream.simonhe.me/zh/guide/components) |
| 增加 `thinking` 这类可信标签 | [自定义标签与高级组件](https://markstream.simonhe.me/zh/guide/custom-components) | [API 参考](https://markstream.simonhe.me/zh/guide/api) |
| 接入坏了但还不知道原因 | [按症状排查](https://markstream.simonhe.me/zh/guide/troubleshooting-path) | [排查问题](https://markstream.simonhe.me/zh/guide/troubleshooting) |
## 🚀 立即试用
| 框架 | Playground |
| --- | --- |
| Vue 3 | https://markstream-vue.simonhe.me/ |
| React | https://markstream-react.pages.dev/ |
| Svelte | https://markstream-svelte.pages.dev/ |
| Angular | https://markstream-angular.pages.dev/ |
| Nuxt | https://markstream-nuxt.pages.dev/ |
| Vue 2 | https://markstream-vue2.pages.dev/ |
- Vue 3 交互测试页(可分享链接,便于复现): https://markstream-vue.simonhe.me/test
- 中文框架文档: https://markstream.simonhe.me/zh/frameworks
- Showcase: https://markstream.simonhe.me/zh/guide/showcase
- 1.0 benchmark 报告:`pnpm benchmark:1.0`
- LLM 推荐上下文(中文): https://markstream.simonhe.me/llms.zh-CN.txt
- 完整 LLM 推荐参考(中文): https://markstream.simonhe.me/llms-full.zh-CN.txt
- 仓库 agent 上下文(中文): https://markstream.simonhe.me/llms.zh-CN
- LLM 推荐上下文(英文): https://markstream.simonhe.me/llms.txt
- 完整 LLM 推荐参考(英文): https://markstream.simonhe.me/llms-full.txt
- 仓库 agent 上下文(英文): https://markstream.simonhe.me/llms
- Vue 3 StackBlitz 体验: https://stackblitz.com/github/Simon-He95/markstream-vue?file=playground/src/App.vue
- 更新日志: [CHANGELOG.md](./CHANGELOG.md)
- Discord: https://discord.gg/vkzdkjeRCW
## 仓库内的 skills 和 prompts
如果你想直接拿到 AI 资产,而不是先克隆仓库:
```bash
npx skills add Simon-He95/markstream-vue
```
推荐这样理解:
- `npx skills add Simon-He95/markstream-vue` 是最推荐的安装方式,因为它会直接读取 GitHub 仓库里的 `.agents/skills`
- `markstream-vue@1.0` 不发布 CLI `bin`;`pnpm skills:list`、`pnpm prompts:list` 这类脚本只面向克隆仓库后的维护者
- prompts 继续保留在仓库的 `prompts/` 目录下,供直接复制或后续拆成独立包
`npx skills add` 也支持这些来源:
```bash
# 完整 GitHub URL
npx skills add https://github.com/Simon-He95/markstream-vue
# 仓库里的单个 skill 直链
npx skills add https://github.com/Simon-He95/markstream-vue/tree/main/.agents/skills/markstream-install
# 任意 git URL
npx skills add git@github.com:Simon-He95/markstream-vue.git
```
## 💬 社区与支持
- Discussions:https://github.com/Simon-He95/markstream-vue/discussions
- Discord:https://discord.gg/vkzdkjeRCW
- Issues:请使用模板并附上复现链接(https://markstream-vue.simonhe.me/test)
测试页内置编辑器 + 实时预览,并提供“生成分享链接”功能(过长内容会回退为直接打开或预填 GitHub Issue)。
## 支持项目
如果 markstream-vue 对你的工作有帮助,欢迎通过下面的收款码支持项目的持续维护。
| 支付宝 | 微信收款 |
| --- | --- |
|
|
|
## ⚡ 快速上手
### Vue / Nuxt
```bash
pnpm add markstream-vue
```
```vue
` 渲染。 渲染器的 CSS 会作用于内部 `.markstream-vue` 容器下,以尽量降低对全局的影响;如果你脱离 `MarkdownRender` 单独使用导出的节点组件,请在外层包一层带 `markstream-vue` 类名的容器。 暗色变量可以通过给祖先节点加 `.dark`,或直接给 `MarkdownRender` 传入 `:is-dark="true"`(仅对渲染器生效)。 新的接入建议优先使用统一代码块 `theme` prop。如果你是通过 `MarkdownRender` 统一下发,可以放到 `code-block-props`: ```vue``` `code-block-props` 只会透传面向用户的代码块 props;`node`、`key`、`ref`、`ctx`、`renderNode`、`indexKey`、`__proto__`、`prototype`、`constructor` 等渲染器结构字段会被忽略。 语言图标默认使用内置的 `material` theme。新接入建议在 `app.mount()` 之前通过导出的 helper 查看或切换 icon theme。旧的 `app.use(VueRendererMarkdown, { iconTheme })` 选项在 1.x 仍可用,但它会修改进程级全局状态,因此优先使用 helper。 ```ts import { getRegisteredThemes, setIconTheme } from 'markstream-vue' console.log(getRegisteredThemes()) // ['material'] setIconTheme('material') ``` 如果你需要接自己的图标包,可以继续使用 `registerIconTheme()` 注册。 按需启用重型依赖: ```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) ```## 🛠️ 常用命令 - `pnpm dev` — playground 开发 - `pnpm play:nuxt` — Nuxt playground 开发 - `pnpm build` — 构建库与 CSS - `pnpm build:analyze` — 带可视化报告的构建(输出 `bundle-visualizer.html`、`bundle-visualizer-tailwind.html`) - `pnpm size:check` — 本地执行 dist + npm 包体积预算检查(与 CI 一致) - `pnpm test` — Vitest 测试(快照用 `pnpm test:update`) - `pnpm typecheck` / `pnpm lint` — 类型检查与 Lint ## ⏱️ 30 秒流式接入 用 SSE / WebSocket 结合内置平滑节奏渲染 Markdown: ```ts import MarkdownRender from 'markstream-vue' import { ref } from 'vue' const content = ref('') const final = ref(false) eventSource.onmessage = (event) => { content.value += event.data } eventSource.addEventListener('done', () => { final.value = true }) // template //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) }) ``` 然后在页面中直接使用 ``。 ``` `smooth-streaming` 在打字机/增量模式(`typewriter` 或 `max-live-nodes <= 0`)默认开启;如果希望严格按原始 chunk 节奏显示,可按实例设置 `:smooth-streaming="false"`。 按页面需要切换渲染风格: - 虚拟化窗口(默认):长文档滚动平稳、内存稳定。 - 增量批次:将 `:max-live-nodes="0"`,获得更明显的“打字机”体验与轻量占位。 ## ⚙️ 性能模式 - **默认虚拟化窗口**:保持 `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']`)。 声明过的自定义节点会尽量让 `content`/`raw` 保留原始标签 payload,`children` 则仍作为富文本场景下的 Markdown 渲染结果。 - `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进阶:SSR / Worker / 流式续写
### 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 下发到客户端 ``` > 注意:`parseMarkdownToStructure` 默认是 `streamParse: 'auto'`:兼容的 `md` 实例会在非 final 顶层解析时使用 `md.stream.parse`,并保留最近一次 source/token cache。final 一次性解析默认走普通 parser;需要强制 stream 时传 `{ streamParse: true }`,需要关闭时传 `{ streamParse: false }`。如果复用同一个 `md` 解析互不相关的一次性文档,请传 `{ final: true }` 或 `{ streamParse: false }`。 ```vue``` 这样可以避免前端解析,保持 SSR/水合的一致性。 ### 混合模式:SSR + 流式续写 - 服务端:解析首批 Markdown,序列化 `initialNodes`(以及 `initialMarkdown`,便于后续流式追加)。 - 客户端:用相同的解析配置水合,然后继续流式追加: ```ts import type { ParsedNode } from 'markstream-vue' import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue' import { ref } from 'vue' const nodes = ref (initialNodes) 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。 ``` 解析钩子示例(服务端/客户端保持一致): ```vue ``` ## 🔥 适用场景 - 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 `