e0a5f57793
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
170 lines
6.2 KiB
Markdown
170 lines
6.2 KiB
Markdown
---
|
|
description: Choose between content and nodes, understand the render pipeline, and wire markstream-vue into Vite, VitePress, Nuxt, and streaming UIs.
|
|
---
|
|
|
|
# Usage & API
|
|
|
|
This page shows how to wire `markstream-vue` into common stacks, how the parser fits into the renderer, and which docs to visit when something looks odd (reset order, Tailwind/UnoCSS layers, VitePress integration).
|
|
|
|
## Choose `content` or `nodes` first
|
|
|
|
| Situation | Recommended input |
|
|
|-----------|-------------------|
|
|
| Docs pages, static articles, low-frequency updates | `content` |
|
|
| SSE, token streaming, AI chat, or frequent incremental updates | `nodes` + `final` |
|
|
| SSR or worker-preparsed content | `nodes` |
|
|
|
|
If you only need built-in configuration, stay in this page and [Props & Options](/guide/props). If you need to replace rendering behavior, jump to [Override Built-in Components](/guide/component-overrides).
|
|
|
|
If your real goal is an AI chat surface, token stream, or SSE response viewer, use the dedicated [AI Chat & Streaming](/guide/ai-chat-streaming) path instead of piecing the docs together manually.
|
|
|
|
If your real goal is a docs site or VitePress theme, use [Docs Site & VitePress](/guide/vitepress-docs-integration) for the end-to-end `content` + `enhanceApp` + CSS setup.
|
|
|
|
## Minimal render
|
|
|
|
```vue twoslash
|
|
<script setup lang="ts">
|
|
import MarkdownRender from 'markstream-vue'
|
|
|
|
const doc = '# Usage example\n\nSupports **streaming** nodes.'
|
|
</script>
|
|
|
|
<template>
|
|
<MarkdownRender custom-id="docs" :content="doc" />
|
|
</template>
|
|
```
|
|
|
|
```css
|
|
@import 'modern-css-reset';
|
|
|
|
@layer components {
|
|
@import 'markstream-vue/index.css';
|
|
}
|
|
```
|
|
|
|
## VitePress + custom tags
|
|
|
|
If this is your main use case rather than a one-off example, continue with the dedicated [Docs Site & VitePress](/guide/vitepress-docs-integration) path after this section.
|
|
|
|
In VitePress, register your custom node component once in `enhanceApp`, then use `custom-html-tags` on `MarkdownRender` to let the parser emit custom nodes automatically.
|
|
|
|
```ts twoslash
|
|
import type { Component } from 'vue'
|
|
import MarkdownRender, { setCustomComponents } from 'markstream-vue'
|
|
// docs/.vitepress/theme/index.ts
|
|
import DefaultTheme from 'vitepress/theme'
|
|
import 'markstream-vue/index.css'
|
|
|
|
declare const ThinkingNode: Component
|
|
|
|
export default {
|
|
extends: DefaultTheme,
|
|
enhanceApp() {
|
|
setCustomComponents('docs', { thinking: ThinkingNode })
|
|
},
|
|
}
|
|
```
|
|
|
|
```md
|
|
<!-- in a VitePress page -->
|
|
<MarkdownRender
|
|
custom-id="docs"
|
|
:custom-html-tags="['thinking']"
|
|
:content="source"
|
|
/>
|
|
```
|
|
|
|
Tip: unknown HTML-like tags (such as `<question>`) render as raw HTML elements once closed. Incomplete or malformed fragments stay as plain text so they do not swallow nearby Markdown. Add the tag name to `custom-html-tags` when you want custom node output (type + attrs/content).
|
|
|
|
## Parser pipeline
|
|
|
|
```ts twoslash
|
|
import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue'
|
|
|
|
const md = getMarkdown()
|
|
|
|
const nodes = parseMarkdownToStructure('# Title', md)
|
|
// pass nodes to <MarkdownRender :nodes="nodes" />
|
|
```
|
|
|
|
- `getMarkdown(msgId?, options?)` returns a configured `markdown-it-ts` instance.
|
|
- `parseMarkdownToStructure(content, md)` transforms a Markdown string into the AST consumed by the renderer.
|
|
- Combine with `setCustomComponents(id?, mapping)` to swap node renderers for a given `custom-id`.
|
|
|
|
## Streaming recommendation
|
|
|
|
For low-frequency updates, passing `content` directly is convenient. For chat-style token streams or long documents, prefer parsing outside the component and passing `nodes` so Vue only reconciles the AST you hand it:
|
|
|
|
```ts twoslash
|
|
import { getMarkdown, parseMarkdownToStructure } from 'markstream-vue'
|
|
|
|
const md = getMarkdown('chat')
|
|
declare const source: string
|
|
declare const isFinalChunk: boolean
|
|
const nodes = parseMarkdownToStructure(source, md, { final: isFinalChunk })
|
|
```
|
|
|
|
```vue twoslash
|
|
<script setup lang="ts">
|
|
import type { BaseNode } from 'markstream-vue'
|
|
import MarkdownRender from 'markstream-vue'
|
|
|
|
const nodes: BaseNode[] = []
|
|
const isFinalChunk = false
|
|
</script>
|
|
|
|
<template>
|
|
<MarkdownRender :nodes="nodes" :final="isFinalChunk" />
|
|
</template>
|
|
```
|
|
|
|
That avoids reparsing the full Markdown string inside `MarkdownRender` on every tiny content update, which is usually the biggest win for SSE / AI output.
|
|
|
|
For a full end-to-end rollout order, peer selection, and chat-specific tuning, continue with [AI Chat & Streaming](/guide/ai-chat-streaming).
|
|
|
|
## Component matrix
|
|
|
|
For a full list of components and props, visit [Components & node renderers](/guide/components). Highlights:
|
|
|
|
- `CodeBlockNode` — Monaco-powered blocks (requires `stream-monaco`).
|
|
- `MarkdownCodeBlockNode` — Shiki-based lightweight highlighting.
|
|
- `MermaidBlockNode` — requires `mermaid` ≥ 11 (no extra CSS).
|
|
- `D2BlockNode` — requires `@terrastruct/d2` (no extra CSS).
|
|
- `ImageNode` — emits `click`, `load`, `error` for custom previews.
|
|
|
|
## Styling reminders
|
|
|
|
1. **Reset first** (`modern-css-reset`, `@tailwind base`, `@unocss/reset`), then import `markstream-vue` styles.
|
|
2. **Use CSS layers** when Tailwind/UnoCSS is active (`@layer components { @import 'markstream-vue/index.css' }`).
|
|
3. **UNO/Tailwind conflicts** — follow the [Tailwind guide](/guide/tailwind) (includes UnoCSS examples) to prevent utilities from overriding renderer styles.
|
|
4. **Peer CSS** — KaTeX needs its own CSS; Mermaid/D2 do not. Monaco does not require extra CSS.
|
|
|
|
## CSS scoping (important)
|
|
|
|
The package CSS is scoped under an internal `.markstream-vue` container to minimize global style conflicts (Tailwind utilities and theme variables included).
|
|
|
|
- When you use `MarkdownRender`, you get this container automatically.
|
|
- If you render exported node components on their own (e.g. `PreCodeNode`, `FootnoteNode`), wrap them with a container element:
|
|
|
|
```vue twoslash
|
|
<script setup lang="ts">
|
|
import type { PreCodeNodeProps } from 'markstream-vue'
|
|
import { PreCodeNode } from 'markstream-vue'
|
|
|
|
const node = {
|
|
type: 'code_block',
|
|
language: 'ts',
|
|
code: 'console.log(1)',
|
|
raw: 'console.log(1)',
|
|
} satisfies PreCodeNodeProps['node']
|
|
</script>
|
|
|
|
<template>
|
|
<div class="markstream-vue">
|
|
<PreCodeNode :node="node" />
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
If visuals still look wrong, reproduce the issue inside the playground (`pnpm play`) and cross-check with the troubleshooting guide before filing a bug.
|