2.0 Migration Guide
Version 2.0 replaces the mdast pipeline with Comark, renders its compact document directly, and moves large rendering runtimes behind optional extensions. The Markdown component and its core display options remain familiar, but parser customization and rich-renderer configuration have changed.
Parser return value
When using @markmend/parser directly, parse() returns the document and
streaming completion information as one result. Replace direct document access
on the parse result:
// Before
const document = await parser.parse(markdown)
// 2.0
const { document, completion } = await parser.parse(markdown)getDocument() continues to return the latest successfully parsed document.
Custom completion functions may continue returning a string, or return
{ markdown, completion } to describe the syntax they completed.
Package changes
The main package remains:
pnpm add vue-stream-markdownInstall rich renderers separately:
pnpm add @stream-markdown/code
pnpm add @stream-markdown/math
pnpm add @stream-markdown/mermaid
pnpm add @stream-markdown/beautiful-mermaidPackage changes:
@markmend/astis replaced by@markmend/parser.@stream-markdown/htmlis removed; native HTML and custom tags are supported by the main package.- Beautiful Mermaid is no longer bundled with
@stream-markdown/mermaid. - Shiki, KaTeX, Mermaid, and Beautiful Mermaid types come from their corresponding extension packages.
Configure rich renderers
In 1.x, provider configuration was passed directly to Markdown:
<Markdown
:shiki-options="shikiOptions"
:katex-options="katexOptions"
:mermaid-options="mermaidOptions"
:cdn-options="cdnOptions"
/>In 2.0, create extension instances and pass them through extensions:
<script setup lang="ts">
import { beautifulMermaid } from '@stream-markdown/beautiful-mermaid'
import { code } from '@stream-markdown/code'
import { math } from '@stream-markdown/math'
import { mermaid } from '@stream-markdown/mermaid'
const extensions = {
code: code({ theme: ['github-light', 'github-dark'] }),
math: math(),
beautifulMermaid: beautifulMermaid(),
mermaid: mermaid(),
}
</script>
<template>
<Markdown :content="content" :extensions="extensions" />
</template>When both diagram extensions are configured, supported diagrams use Beautiful Mermaid and other diagram types fall back to Mermaid.
Replace parser APIs
| 1.x | 2.0 |
|---|---|
mdastOptions | parserOptions |
| Markmend preprocessing hooks | completion / completionSteps |
nodeRenderers keyed by mdast node type | components keyed by HTML/Comark tag |
components for shared UI controls | uiComponents |
getMarkdownParser() | Removed |
getParsedNodes() | getDocument() |
getProcessedContent() | Removed |
The removed lifecycle hooks include normalize, preprocess, parseMarkdownIntoBlocks, postnormalize, and postprocess. Use completion for a complete custom function or completionSteps to replace selected built-in steps. The built-in completion functions are now exported with a complete* prefix (for example, completeLink and completeMath) and are also available through defaultCompletionSteps.
Custom completion
<script setup lang="ts">
function completion(markdown: string) {
return markdown.endsWith('**') ? markdown : markdown + '**'
}
</script>
<template>
<Markdown :content="content" :completion="completion" />
</template>Completion runs only in streaming mode. Static mode parses the original source.
To keep the default pipeline and replace one rule, pass a partial step map:
import { completeLink } from 'vue-stream-markdown'
const completion = {
completionSteps: {
link: (markdown, context) => completeLink(markdown, context),
},
}Comark plugins
<script setup lang="ts">
import myPlugin from './my-comark-plugin'
const parserOptions = {
plugins: [myPlugin()],
}
</script>
<template>
<Markdown :content="content" :parser-options="parserOptions" />
</template>Replace custom renderers
In 1.x, nodeRenderers received mdast-oriented nodes. In 2.0, map the emitted tag name directly:
<script setup lang="ts">
import CustomHeading from './custom-heading.vue'
import GitHubCard from './github-card.vue'
const components = {
h2: CustomHeading,
github: GitHubCard,
}
</script>
<template>
<Markdown :content="content" :components="components" />
</template>The same mapping handles native Markdown elements and custom HTML-like tags.
For shared controls such as Button, move UI replacements from the 1.x components prop to uiComponents:
<Markdown :ui-components="{ Button: CustomButton }" />For direct renderer reuse:
| 1.x | 2.0 |
|---|---|
NODE_RENDERERS | Named renderers, such as CodeBlockRenderer and LinkRenderer. |
UI.CodeBlock / UI.Table | Content overrides through components, with CodeBlockRenderer / TableRenderer for built-in behavior. |
NodeList | MarkdownNodes, with Comark nodes instead of mdast nodes. |
Custom renderers now receive a Comark element tuple as node, plus nodeKey and loading. Forward these props when reusing a built-in renderer. MarkdownNodes uses nodes for its child list; the old deep, blocks, and nodeRenderers props are removed. See Components for props and examples.
Share configuration across messages
MarkdownProvider can supply extensions and theme defaults to a message list:
<MarkdownProvider :extensions="extensions">
<Markdown
v-for="message in messages"
:key="message.id"
:content="message.content"
/>
</MarkdownProvider>An individual Markdown can override a provider value when one message needs different behavior.
Migration checklist
- Install only the rich-renderer packages your application uses.
- Move Shiki, KaTeX, Mermaid, and CDN options into extension factories.
- Replace
mdastOptionswithparserOptionsorcompletion. - Move content overrides to tag-based
componentsand shared-control replacements touiComponents. - Replace parsed-node access with
getDocument(). - Remove
@stream-markdown/htmland any mdast compatibility code. - Import
katex/dist/katex.min.csswhen loading KaTeX locally. - Test custom tags, security rules, streaming-to-static transitions, and extension fallbacks.