--- url: /roadmap.md --- # 🗺 Roadmap Our future plans focus on enhancing the library's capabilities for building modern, accessible, and high-performance AI chat interfaces. ## ✹ Accomplished ### 🏗 Core & Engine * \[x] **BlockTransformer**: Cross-framework architecture for consistent typewriter effects. * \[x] **Syntax Refinement**: Enhanced boundary parsing, commonmark compliance, and edge-case rendering. * \[x] **Incremental Engine**: State-aware parsing for $O(N)$ performance. * \[x] **Dual-Engine Architecture**: Support for both `marked` (fast, streaming-optimized) and `micromark` (stable, CommonMark-compliant) engines with tree-shaking optimization. * \[x] **Micromark Enhancement**: Improved HTML parsing and stability. * \[x] **Marked Enhancement**: Extended `marked` with footnotes, math, custom containers, and inline HTML parsing support. ### 🎚 Design System & Theme * \[x] **@incremark/theme**: Unified styles with DesignToken support in a separate package. * \[x] **ThemeProvider**: Context-based styling for all components. * \[x] **Thematic Components**: Built-in support for specialized markdown blocks. ### 🍱 Framework Components * \[x] **@incremark/vue**: Full-featured Vue component library. * \[x] **@incremark/react**: Full-featured React component library. * \[x] **@incremark/svelte**: Full-featured Svelte component library. * \[x] **@incremark/solid**: Full-featured Solid component library. * \[x] **IncremarkContent**: Declarative, easy-to-use entry component for all frameworks. ### 🔌 Features & Extensions * \[x] **GFM Support**: Full support for GitHub Flavored Markdown. * \[x] **Mermaid Support**: Integrated support for Mermaid diagrams within Markdown. * \[x] **Math Support**: Robust support for LaTeX math formulas via KaTeX. * \[x] **Custom Rendering**: Full support for custom markdown components. * \[x] **Custom Code Blocks**: Flexible configuration for partial or full rendering takeover. * \[x] **Custom Containers**: Support for `:::` container syntax. * \[x] **Footnotes**: Full support for markdown footnotes. * \[x] **HTML Parsing**: Robust handling of embedded HTML content. *** ## 🚀 Upcoming Features ### 🛠 Markdown & Tooling * \[x] **Code Component Refactoring**: Decouple Mermaid and Default renderers to allow for better composition and customization. * \[x] **DevTools Rewrite**: Rebuilding DevTools using Svelte for better DX with i18n support (zh-CN/en-US), multi-parser monitoring, and framework-agnostic design. * \[x] **sliceAST Optimization**: Simplified code structure, removed dead code; per-block processing ensures performance. * \[x] **Internationalization (i18n)**: Built-in multi-language support with ConfigProvider. * \[x] **Accessibility (A11y)**: Enhanced screen reader support and ARIA standards. * \[x] **SSR Support**: Optimization for Server-Side Rendering (Nuxt/Next.js). ### ⚡ Performance Optimization * \[x] **Shiki Stream Optimization**: Improve streaming code highlighting performance across all frameworks. * \[x] **Block Component Rendering**: Optimize block-level component rendering performance, reduce unnecessary re-renders. ### 🏗 Big Vision: Incremental Chat UI Kit A comprehensive set of pre-built UI components powered by the Incremark engine. * \[ ] **@incremark/chat-core**: Logic layer for message management, A2UI protocol, and mainstream LLM SDK adaptation. * \[ ] **@incremark/chat-vue**: High-level chat components for Vue. * \[ ] **UI Adapters**: First-class support for `element-plus` and `shadcn-vue`. * \[ ] **@incremark/chat-react**: High-level chat components for React. * \[ ] **@incremark/chat-svelte**: High-level chat components for Svelte. *** ### 🔌 Plugin System * \[x] **Micromark Extensions**: Full support for `micromark` syntax extensions. * \[x] **mdast Extensions**: Full support for `mdast-util-from-markdown` AST extensions. * \[x] **Marked Extensions**: Custom token transformers for the `marked` engine. *** ## 🔮 Long-term Research * \[ ] **Collaborative Editing**: Researching solutions including: 1. Tiptap markdown parsing based on `micromark`, 2. Incremental appending scheme based on `incremark`. --- --- url: /zh/roadmap.md --- # 🗺 路线囟 我们未来的计划䞓泚于增区库的胜力以构建现代、无障碍䞔高性胜的 AI 聊倩界面。 ## ✹ 已完成 ### 🏗 栞心匕擎 * \[x] **BlockTransformer**: 跚框架打字机效果实现确保枲染䞀臎性。 * \[x] **语法完善**: 修倍蟹界情况解析䞎枲染增加曎完善的 commonmark 测试甚䟋。 * \[x] **增量解析**: 实现 O(N) 性胜的状态感知解析匕擎。 * \[x] **双匕擎架构**: 支持 `marked`极速流匏䌘化和 `micromark`皳定 CommonMark 兌容双匕擎支持 tree-shaking 䌘化。 * \[x] **Micromark 增区**: 提升 HTML 解析胜力䞎皳定性。 * \[x] **Marked 增区**: 䞺 `marked` 扩展脚泚、数孊公匏、自定义容噚、内联 HTML 解析等功胜。 ### 🎚 讟计系统䞎䞻题 * \[x] **@incremark/theme**: 统䞀各组件库样匏支持 DesignToken并拆分䞺独立子包。 * \[x] **ThemeProvider**: 统䞀的样匏䞊䞋文管理组件。 * \[x] **䞻题组件支持**: 内眮倚种 Markdown 块级䞻题组件。 ### Bento 组件库 * \[x] **@incremark/vue**: 完敎的 Vue 组件集成。 * \[x] **@incremark/react**: 完敎的 React 组件集成。 * \[x] **@incremark/svelte**: 完敎的 Svelte 组件集成。 * \[x] **@incremark/solid**: 完敎的 Solid 组件集成。 * \[x] **IncremarkContent**: 简单易甚的声明匏入口组件。 ### 🔌 功胜䞎扩展 * \[x] **GFM 支持**: 支持 GFM 语法。 * \[x] **Mermaid 支持**: 支持圚 Markdown 䞭嵌入 Mermaid 囟衚。 * \[x] **Math 支持**: 支持圚 Markdown 䞭嵌入 Math 公匏。 * \[x] **自定义组件**: 支持自定义 Markdown 枲染组件。 * \[x] **自定义代码块**: 支持党接管或完成时枲染接管。 * \[x] **自定义容噚**: 支持 `:::` 容噚块语法。 * \[x] **脚泚支持**: 完敎的 Markdown 脚泚功胜。 * \[x] **HTML 解析**: 支持圚 Markdown 䞭嵌入 HTML 标筟。 *** ## 🚀 即将进行 ### 🛠 Markdown 䞎工具 * \[x] **Code 组件重构**: 解耊 Mermaid 䞎默讀枲染噚提升定制化胜力。 * \[x] **devtools 重构**: 䜿甚 Svelte 重构匀发工具支持囜际化䞭英文、倚解析噚监控、框架无关讟计提升匀发䜓验。 * \[x] **sliceAST 䌘化**: 简化代码结构移陀死代码按 block 倄理确保性胜。 * \[x] **i18n 囜际化**: 内眮倚语蚀支持提䟛 ConfigProvider 党局配眮。 * \[x] **a11y 无障碍**: 完善屏幕阅读噚支持䞎 ARIA 规范。 * \[x] **SSR 支持**: 针对 Nuxt/Next.js 的服务端枲染䌘化。 ### ⚡ 性胜䌘化 * \[x] **Shiki Stream 䌘化**: 䌘化各框架流匏代码高亮性胜。 * \[x] **Block 组件枲染䌘化**: 䌘化块级组件枲染性胜减少䞍必芁的重新枲染。 ### 🏗 倧计划: 基于增量枲染的 chat-ui 组件库 利甚 Incremark 匕擎打造的䞀套匀箱即甚的 AI 聊倩 UI 组件。 * \[ ] **@incremark/chat-core**: 消息管理逻蟑层支持 A2UI 协议及䞻流 SDK 适配。 * \[ ] **@incremark/chat-vue**: 基于 Vue 的高阶聊倩组件。 * \[ ] **UI 适配噚**: 䌘先适配 `element-plus` 和 `shadcn-vue`。 * \[ ] **@incremark/chat-react**: 基于 React 的高阶聊倩组件。 * \[ ] **@incremark/chat-svelte**: 基于 Svelte 的高阶聊倩组件。 *** ### 🔌 插件系统 * \[x] **Micromark 扩展**: 完敎支持 `micromark` 语法扩展。 * \[x] **mdast 扩展**: 完敎支持 `mdast-util-from-markdown` AST 扩展。 * \[x] **Marked 扩展**: 䞺 `marked` 匕擎提䟛自定义 Token 蜬换噚。 *** ## 🔮 长期研究 * \[ ] **协䜜猖蟑**: 1. 基于 micromark 的 tiptap markdown 解析方案 2. 基于 incremark 的增量远加方案。 --- --- url: /examples/anthropic.md --- # Anthropic Integration Using the `@anthropic-ai/sdk` library. ## Example ```ts import Anthropic from '@anthropic-ai/sdk' import { IncremarkContent } from '@incremark/react' const anthropic = new Anthropic({ apiKey: 'YOUR_API_KEY', }) function App() { const [stream, setStream] = useState(null) async function startChat() { async function* getStream() { const stream = await anthropic.messages.create({ max_tokens: 1024, messages: [{ role: 'user', content: 'Hello, Claude' }], model: 'claude-3-opus-20240229', stream: true, }) for await (const chunk of stream) { if (chunk.type === 'content_block_delta') { yield chunk.delta.text } } } setStream(() => getStream) } return ( <> ) } ``` --- --- url: /zh/examples/anthropic.md --- # Anthropic 集成 䜿甚 `@anthropic-ai/sdk` 库。 ## 瀺䟋 ```ts import Anthropic from '@anthropic-ai/sdk' import { IncremarkContent } from '@incremark/react' const anthropic = new Anthropic({ apiKey: 'YOUR_API_KEY', }) function App() { const [stream, setStream] = useState(null) async function startChat() { async function* getStream() { const stream = await anthropic.messages.create({ max_tokens: 1024, messages: [{ role: 'user', content: 'Hello, Claude' }], model: 'claude-3-opus-20240229', stream: true, }) for await (const chunk of stream) { if (chunk.type === 'content_block_delta') { yield chunk.delta.text } } } setStream(() => getStream) } return ( <> ) } ``` --- --- url: /api.md --- # API Reference A centralized reference for all Incremark types and components. ## Components ### `` The main component for rendering Markdown content. **Props (`IncremarkContentProps`)**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `content` | `string` | - | The Markdown string to render (content mode). | | `stream` | `() => AsyncGenerator` | - | Async generator function for streaming content (stream mode). | | `isFinished` | `boolean` | `false` | Whether the content generation is finished (required for content mode). | | `incremarkOptions` | `UseIncremarkOptions` | - | Configuration options for the parser and typewriter effect. | | `components` | `ComponentMap` | `{}` | Custom components to override default element rendering. | | `customContainers` | `Record` | `{}` | Custom container components for `::: name` syntax. | | `customCodeBlocks` | `Record` | `{}` | Custom code block components for specific languages. | | `codeBlockConfigs` | `Record` | `{}` | Configuration for code blocks (e.g., `takeOver`). | | `showBlockStatus` | `boolean` | `false` | Whether to visualize block processing status (pending/completed). | | `pendingClass` | `string` | `'incremark-pending'` | CSS class applied to pending blocks. | | `devtools` | `IncremarkDevTools` | - | DevTools instance to register with for debugging. | | `devtoolsId` | `string` | *Auto-generated* | Unique identifier for this parser in DevTools. | | `devtoolsLabel` | `string` | `devtoolsId` | Display label for this parser in DevTools. | ### `` A container that automatically scrolls to the bottom when content updates. **Props**: | Prop | Type | Default | Description | |------|------|---------|-------------| | `enabled` | `boolean` | `true` | Whether auto-scroll functionality is active. | | `threshold` | `number` | `50` | Distance in pixels from bottom to trigger auto-scroll. | | `behavior` | `ScrollBehavior` | `'instant'` | Scroll behavior (`'auto'`, `'smooth'`, `'instant'`). | ## Composables / Hooks ### `useIncremark` The core hook for advanced usage and fine-grained control. **Options (`UseIncremarkOptions`)**: | Option | Type | Default | Description | |--------|------|---------|-------------| | `gfm` | `boolean` | `true` | Enable GitHub Flavored Markdown support. | | `math` | `boolean` | `true` | Enable Math (KaTeX) support. | | `htmlTree` | `boolean` | `true` | Enable parsing of raw HTML tags. | | `containers` | `boolean` | `true` | Enable custom container syntax `:::`. | | `typewriter` | `TypewriterOptions` | - | Configuration for typewriter effect. | **Returns (`UseIncremarkReturn`)**: | Property | Type | Description | |----------|------|-------------| | `blocks` | `Ref` | Reactive array of parsed blocks with stable IDs. | | `append` | `(chunk: string) => void` | Append new content chunk to the parser. | | `render` | `(content: string) => void` | Render a complete or updated content string. | | `reset` | `() => void` | Reset parser state and clear all blocks. | | `finalize` | `() => void` | Mark all blocks as completed. | | `isDisplayComplete` | `Ref` | Whether the typewriter effect has finished displaying all content. | ## Configuration Types ### `TypewriterOptions` | Option | Type | Default | Description | |--------|------|---------|-------------| | `enabled` | `boolean` | `false` | Enable typewriter effect. | | `charsPerTick` | `number \| [number, number]` | `2` | Characters to reveal per tick (or range). | | `tickInterval` | `number` | `50` | ms between ticks. | | `effect` | `'none' \| 'fade-in' \| 'typing'` | `'none'` | Animation style. | | `cursor` | `string` | `'|'` | Cursor character for typing effect. | --- --- url: /zh/api.md --- # API 参考文档 Incremark 所有类型和组件的集䞭参考。 ## 组件 (Components) ### `` 枲染 Markdown 内容的䞻芁组件。 **Props (`IncremarkContentProps`)**: | 属性 | 类型 | 默讀倌 | 诎明 | |------|------|--------|------| | `content` | `string` | - | 芁枲染的 Markdown 字笊䞲content 暡匏。 | | `stream` | `() => AsyncGenerator` | - | 甚于流匏内容的匂步生成噚凜数stream 暡匏。 | | `isFinished` | `boolean` | `false` | 内容生成是吊完成content 暡匏必需。 | | `incremarkOptions` | `UseIncremarkOptions` | - | 解析噚和打字机效果的配眮选项。 | | `components` | `ComponentMap` | `{}` | 自定义组件甚于芆盖默讀元玠的枲染。 | | `customContainers` | `Record` | `{}` | 甚于 `::: name` 语法的自定义容噚组件。 | | `customCodeBlocks` | `Record` | `{}` | 特定语蚀的自定义代码块组件。 | | `codeBlockConfigs` | `Record` | `{}` | 代码块配眮䟋劂 `takeOver`。 | | `showBlockStatus` | `boolean` | `false` | 是吊可视化块的倄理状态pending/completed。 | | `pendingClass` | `string` | `'incremark-pending'` | 应甚于 pending 状态块的 CSS 类。 | | `devtools` | `IncremarkDevTools` | - | 芁泚册的 DevTools 实䟋甚于调试。 | | `devtoolsId` | `string` | *自劚生成* | 圚 DevTools 䞭歀解析噚的唯䞀标识笊。 | | `devtoolsLabel` | `string` | `devtoolsId` | 圚 DevTools 䞭歀解析噚的星瀺标筟。 | ### `` 圓内容曎新时自劚滚劚到底郚的容噚组件。 **Props**: | 属性 | 类型 | 默讀倌 | 诎明 | |------|------|--------|------| | `enabled` | `boolean` | `true` | 是吊启甚自劚滚劚功胜。 | | `threshold` | `number` | `50` | 觊发自劚滚劚的底郚距犻阈倌像玠。 | | `behavior` | `ScrollBehavior` | `'instant'` | 滚劚行䞺 (`'auto'`, `'smooth'`, `'instant'`)。 | ## 组合匏凜数 / Hooks ### `useIncremark` 甚于高级甚法和细粒床控制的栞心 Hook。 **选项 (`UseIncremarkOptions`)**: | 选项 | 类型 | 默讀倌 | 诎明 | |------|------|--------|------| | `gfm` | `boolean` | `true` | 启甚 GitHub Flavored Markdown 支持。 | | `math` | `boolean` | `true` | 启甚数孊公匏 (KaTeX) 支持。 | | `htmlTree` | `boolean` | `true` | 启甚原始 HTML 标筟解析。 | | `containers` | `boolean` | `true` | 启甚自定义容噚语法 `:::`。 | | `typewriter` | `TypewriterOptions` | - | 打字机效果配眮。 | **返回倌 (`UseIncremarkReturn`)**: | 属性 | 类型 | 诎明 | |------|------|------| | `blocks` | `Ref` | 具有皳定 ID 的解析块响应匏数组。 | | `append` | `(chunk: string) => void` | 向解析噚远加新的内容块。 | | `render` | `(content: string) => void` | 枲染完敎或曎新的内容字笊䞲。 | | `reset` | `() => void` | 重眮解析噚状态并枅空所有块。 | | `finalize` | `() => void` | 将所有块标记䞺已完成。 | | `isDisplayComplete` | `Ref` | 打字机效果是吊已星瀺完所有内容。 | ## 配眮类型 ### `TypewriterOptions` | 选项 | 类型 | 默讀倌 | 诎明 | |------|------|--------|------| | `enabled` | `boolean` | `false` | 启甚打字机效果。 | | `charsPerTick` | `number \| [number, number]` | `2` | 每次星瀺的字笊数或范囎。 | | `tickInterval` | `number` | `50` | 曎新闎隔毫秒。 | | `effect` | `'none' \| 'fade-in' \| 'typing'` | `'none'` | 劚画风栌。 | | `cursor` | `string` | `'|'` | 打字效果的光标字笊。 | --- --- url: /advanced/architecture.md --- # Architecture This document explains the internal architecture of Incremark, helping you understand how the library achieves high-performance streaming markdown rendering. ## Overall Architecture ``` ┌─────────────────────────────────────────────────────────────────┐ │ IncremarkContent │ │ (Declarative component, handles content/stream input) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ useIncremark │ │ (State management, reactive wrapper, typewriter coordination) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ IncremarkParser │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ Dual-Engine AST Builder │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ │ │ MarkedAstBuilder│ │MicromarkAstBuilder│ │ │ │ │ │ (Default, Fast) │ │ (Stable, Strict) │ │ │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ Boundary │ │ Definition │ │ Footnote │ │ │ │ Detector │ │ Manager │ │ Manager │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ BlockTransformer │ │ (Typewriter effect, character-level incremental rendering) │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ Plugins │ │ Chunk │ │ TextChunk │ │ │ │ System │ │ Animation │ │ Tracking │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ Renderer │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Vue │ │ React │ │ Svelte │ │ │ │ Components │ │ Components │ │ Components │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Dual-Engine Architecture Incremark supports two parsing engines that can be switched at runtime: ### MarkedAstBuilder (Default) The `marked` engine is optimized for streaming performance: * **Speed**: Extremely fast tokenization, ideal for real-time AI chat * **Extensions**: Custom extensions for footnotes, math, containers, inline HTML * **Trade-off**: Slightly less strict CommonMark compliance ```ts // Internal: packages/core/src/parser/ast/MarkedAstBuildter.ts class MarkedAstBuilder implements IAstBuilder { // Custom marked extensions private extensions = [ createFootnoteDefinitionExtension(), createBlockMathExtension(), createInlineMathExtension(), createContainerExtension(), createInlineHtmlExtension() ] } ``` ### MicromarkAstBuilder The `micromark` engine prioritizes correctness and extensibility: * **Compliance**: Strict CommonMark specification adherence * **Ecosystem**: Full access to micromark/mdast plugin ecosystem * **Trade-off**: Slightly higher overhead for parsing ```ts // Internal: packages/core/src/parser/ast/MicromarkAstBuilder.ts class MicromarkAstBuilder implements IAstBuilder { // Uses mdast-util-from-markdown with micromark extensions } ``` ### Engine Selection Both engines produce identical mdast output, ensuring consistent rendering: ```ts // Default: uses marked (fast mode) const parser = new IncremarkParser({ gfm: true, math: true }) // To use micromark (import separately for tree-shaking) import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = new IncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true, math: true }) ``` ## Core Components ### IncremarkParser The central coordinator that manages the incremental parsing pipeline: | Component | Responsibility | |-----------|---------------| | **BoundaryDetector** | Identifies stable boundaries (empty lines, new headings) to commit completed blocks | | **AstBuilder** | Constructs mdast nodes from markdown text using the selected engine | | **DefinitionManager** | Tracks link/image definitions across the document | | **FootnoteManager** | Manages footnote definitions and references | ### BlockTransformer Handles the typewriter animation layer: | Component | Responsibility | |-----------|---------------| | **Plugins System** | Extensible plugin architecture for custom behavior | | **Chunk Animation** | Manages the queue of text chunks to animate | | **TextChunk Tracking** | Tracks which characters have been "played" for smooth animation | ### Renderer Framework-specific rendering components: * **Vue**: `@incremark/vue` - Uses Vue 3.5 Composition API * **React**: `@incremark/react` - Uses React 18 hooks * **Svelte**: `@incremark/svelte` - Uses Svelte 5 runes All renderers share the same core logic and produce identical DOM output. ## Data Flow ```mermaid sequenceDiagram participant App as Application participant IC as IncremarkContent participant UI as useIncremark participant P as Parser participant BT as BlockTransformer participant R as Renderer App->>IC: content += chunk IC->>UI: append(chunk) UI->>P: parse(markdown) Note over P: Boundary Detection P->>P: Find stable boundaries P->>P: Cache completed blocks P->>P: Re-parse only pending block P-->>UI: blocks[] UI->>BT: transform(blocks) Note over BT: Animation Processing BT->>BT: Diff with previous state BT->>BT: Create TextChunks for new text BT->>BT: Queue for typewriter effect BT-->>UI: animatedBlocks[] UI->>R: render(animatedBlocks) R->>R: Selective DOM update ``` ## Performance Optimizations ### 1. Incremental Line Parsing Only new lines are parsed; completed blocks are cached: ```ts // Simplified concept if (line.isNewlyAdded) { parse(line) } else if (block.isCompleted) { return cachedAST[block.id] } ``` ### 2. Stable Block IDs Each block receives a stable ID, enabling efficient React/Vue reconciliation: ```ts interface Block { id: string // Stable across updates node: RootContent status: 'pending' | 'completed' } ``` ### 3. AST Incremental Appending New nodes are appended to the existing tree without rebuilding: ```ts // Instead of: root = parse(entireMarkdown) // We do: existingRoot.children.push(...newNodes) ``` ### 4. Context Caching Parser state is preserved between chunks for efficient resumption: ```ts interface ParserContext { inFencedCode: boolean inContainer: boolean listStack: ListInfo[] blockquoteDepth: number } ``` ## Extension Points Incremark provides multiple extension points: | Level | Extension Type | Example | |-------|---------------|---------| | **Parser** | micromark extensions | Custom syntax | | **Parser** | mdast extensions | Custom AST nodes | | **Parser** | marked transformers | Custom token handling | | **Renderer** | Custom components | Replace heading rendering | | **Renderer** | Custom code blocks | Echarts, Mermaid | | **Renderer** | Custom containers | Warning, Info boxes | See [Extensions](/advanced/extensions) for detailed documentation. --- --- url: /features/auto-scroll.md --- # Auto Scroll ## Using AutoScrollContainer ::: code-group ```vue [Vue] ``` ```tsx [React] import { useRef } from 'react' import { IncremarkContent, AutoScrollContainer } from '@incremark/react' function App() { const scrollRef = useRef(null) return ( ) } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent, AutoScrollContainer } from '@incremark/solid' function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) return ( ) } ``` ::: ## Props | Prop | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `true` | Enable auto scroll | | `threshold` | `number` | `50` | Bottom threshold (pixels) | | `behavior` | `ScrollBehavior` | `'instant'` | Scroll behavior | ## Exposed Methods | Method | Description | |---|---| | `scrollToBottom()` | Force scroll to bottom | | `isUserScrolledUp()` | Whether user manually scrolled up | ## Behavior * Auto scrolls to bottom when content updates. * Pauses auto scroll when user scrolls up. * Resumes auto scroll when user scrolls back to bottom. --- --- url: /features/basic-usage.md --- # Basic Usage **IncremarkContent Component Complete Guide** ## Two Input Modes 1. **content mode**: Pass accumulated string + isFinished flag 2. **stream mode**: Pass function returning AsyncGenerator ## Props Reference ```ts interface IncremarkContentProps { // Input (Choose one) content?: string // Accumulated string stream?: () => AsyncGenerator // Async generator function // Status isFinished?: boolean // Stream finished flag (Required for content mode) // Configuration incremarkOptions?: UseIncremarkOptions // Parser + Typewriter config // Custom Rendering components?: ComponentMap // Custom components customContainers?: Record customCodeBlocks?: Record codeBlockConfigs?: Record // Styling showBlockStatus?: boolean // Show block status border pendingClass?: string // CSS class for pending block } ``` ### UseIncremarkOptions ```ts interface UseIncremarkOptions { // Parser Options gfm?: boolean // GFM support (tables, tasklists, etc.) math?: boolean | MathOptions // Math formula support htmlTree?: boolean // HTML fragment parsing containers?: boolean // ::: container syntax // Typewriter Options typewriter?: { enabled?: boolean charsPerTick?: number | [number, number] tickInterval?: number effect?: 'none' | 'fade-in' | 'typing' cursor?: string } } interface MathOptions { // Enable TeX style \(...\) and \[...\] syntax tex?: boolean } ``` ### Math Configuration By default, `math: true` only supports `$...$` and `$$...$$` syntax. If you need to support TeX/LaTeX style `\(...\)` and `\[...\]` delimiters, enable the **tex** option: ```ts // Enable TeX style delimiters const options = { math: { tex: true } } ``` This is useful when processing academic papers or outputs from certain AI tools. ## Advanced: Using `useIncremark` When finer control is needed: ::: code-group ```vue [Vue] ``` ```tsx [React] import { useIncremark, Incremark } from '@incremark/react' function App() { const { blocks, append, finalize, reset } = useIncremark({ gfm: true }) async function handleStream(stream) { reset() for await (const chunk of stream) { append(chunk) } finalize() } return } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { useIncremark, Incremark } from '@incremark/solid' function App() { const { blocks, append, finalize, reset } = useIncremark({ gfm: true }) async function handleStream(stream) { reset() for await (const chunk of stream) { append(chunk) } finalize() } return } ``` ::: ### useIncremark Return Values | Property | Type | Description | |---|---|---| | `blocks` | `Block[]` | All blocks (with stable ID) | | `markdown` | `string` | Accumulated Markdown | | `append(chunk)` | `Function` | Append content | | `finalize()` | `Function` | Complete parsing | | `reset()` | `Function` | Reset state | | `render(content)` | `Function` | Render once | | `isDisplayComplete` | `boolean` | Is typewriter effect complete | --- --- url: /advanced/benchmark.md --- # Benchmark This page describes how to run performance benchmarks comparing Incremark with other Markdown streaming parsers. ## Parsers Tested | Parser | Approach | Complexity | Description | |--------|----------|------------|-------------| | **Incremark** | Incremental parsing | O(n) | Only parses new content | | **Streamdown** | Full re-parsing | O(n²) | Re-parses entire content each time | | **markstream-vue** | Full re-parsing | O(n²) | Re-parses entire content each time | | **ant-design-x** | Full re-parsing | O(n²) | Based on Marked | ## Test Methodology 1. Read all `.md` files from `test-data/` directory 2. Split content into small chunks (5 chars each, simulating AI token-by-token output) 3. For each parser: * **Incremark**: Uses `append()` method - only parses new content * **Others**: Accumulates string and re-parses entire content each time 4. Measure total time, per-chunk average, and memory usage ## Run Benchmark ### Clone Repository ```bash git clone https://github.com/kingshuaishuai/incremark.git cd incremark/benchmark-compare ``` ### Install Dependencies ```bash pnpm install ``` ### Add Test Data Place your Markdown files in the `test-data/` directory: ```bash # Example: copy some markdown files cp /path/to/your/*.md test-data/ ``` ### Run ```bash # Standard run pnpm benchmark # With garbage collection (more accurate memory stats) pnpm benchmark:gc ``` ## Output The benchmark generates: * **Console output**: Summary table with timing comparisons * **benchmark-results.json**: Detailed results in JSON format ### Sample Output ``` 📊 Performance Summary (sorted by lines) | filename | lines | chars | Incremark | Streamdown | vs Streamdown | |-------------------|-------|---------|-----------|------------|---------------| | short-doc.md | 91 | 2,341 | 12.0 | 50.5 | 4.2x | | medium-doc.md | 147 | 4,123 | 9.0 | 58.8 | 6.6x | | long-doc.md | 391 | 12,456 | 19.1 | 208.4 | 10.9x | | extra-long-doc.md | 916 | 28,912 | 87.7 | 1441.1 | 16.4x | 📈 Performance Summary: - Incremark total: 127.8 ms - Streamdown total: 1758.8 ms (13.8x slower) ``` ## Expected Results | Document Size | Lines | Incremark Advantage | |---------------|-------|---------------------| | Short | ~100 | 4-6x faster | | Medium | ~400 | 10x+ faster | | Long | ~900 | 16-65x faster | ::: tip Key Insight **The longer the document, the greater the advantage of incremental parsing.** This is because: * Incremark: O(n) - only processes new content * Others: O(n²) - re-processes entire accumulated content on each chunk ::: ## Benchmark Code The benchmark script is located at `benchmark-compare/benchmark.ts`. Key implementation: ```typescript // Incremark: O(n) incremental parsing const parser = createIncremarkParser() for (const chunk of chunks) { parser.append(chunk) // Only parses new content } parser.finalize() // Others: O(n²) full re-parsing let accumulated = '' for (const chunk of chunks) { accumulated += chunk parseMarkdown(accumulated) // Re-parses entire content } ``` ## Contributing Test Data We welcome contributions of real-world Markdown files for benchmarking. Please ensure: 1. Files are reasonably sized (100-1000+ lines) 2. Content is appropriate for public sharing 3. Files represent typical AI output scenarios Submit via pull request to the `benchmark-compare/test-data/` directory. --- --- url: /guide/comparison.md --- # Comparison with Other Solutions This guide provides a deep technical comparison between **Incremark**, **Ant Design X Markdown**, and **MarkStream Vue**, analyzing their architectural implementation of streaming Markdown rendering. ## Architecture & Flow ### 1. Incremark (Our Solution) **Strategy: Incremental Parsing + Structural Typewriter Animation** ```mermaid graph TD Input["Streaming Chunk (e.g. 'ng')"] --> Parser["IncremarkParser (Incremental)"] subgraph Core ["Incremental Engine"] Parser --> Boundary["Boundary Detection (State-aware)"] Boundary --> Completed["Completed Blocks (Cached)"] Boundary --> Pending["Pending Block (Updating)"] end Pending --> Transformer["BlockTransformer (Animation Manager)"] Transformer --> AST["Incremental AST Append (TextChunk tracking)"] AST --> Renderer["Framework Renderer (React/Vue)"] Renderer --> DOM["Targeted Patching"] ``` * **Key Advantage**: Only parses what is new or unstable. Animation happens at the AST node level, avoiding re-traversal of stable nodes. Performance is **O(N)**. *** ### 2. Ant Design X (`x-markdown`) **Strategy: Regex Repair + Full Re-parsing (Marked)** ```mermaid graph TD Input["Streaming String"] --> Hook["useStreaming (Regex Interception)"] subgraph Logic ["Repair Logic"] Hook --> Regex["STREAM_INCOMPLETE_REGEX (Detects broken links/images/tables)"] Regex --> Buffer["Buffer (Wait for complete Token)"] end Buffer --> Marked["Marked.js (Full Re-parse)"] Marked --> HTML["HTML String"] HTML --> ReactParser["html-react-parser (React Conversion)"] ReactParser --> Animation["AnimationText (Text Slicing)"] Animation --> DOM["React DOM"] ``` * **Key Advantage**: Robust visual state patching via regex. However, it requires a full re-parse of the entire accumulated string on every update. Performance is **O(N²)**. *** ### 3. MarkStream Vue **Strategy: Full Re-parsing + Virtualized/Batched Rendering (markdown-it)** ```mermaid graph TD Input["Full Markdown String"] --> PreProcess["Regex Patching (parseMarkdownToStructure)"] PreProcess --> MarkdownIt["markdown-it (Full Re-parse)"] subgraph Render ["Optimized Rendering Layer"] MarkdownIt --> Batch["Batch Rendering (requestIdleCallback)"] Batch --> Virtual["Virtualization (Render only visible nodes)"] end Virtual --> VueDOM["Vue Component Tree"] ``` * **Key Advantage**: Accepts the cost of re-parsing but optimizes the DOM layer via virtualization and idling batch updates. Perfect for viewing extremely large history or static documents. *** ## Technical Comparison Matrix | Dimension | Ant Design X (epx) | MarkStream Vue (epx2) | Incremark (core) | | :--- | :--- | :--- | :--- | | **Parsing Engine** | `marked` | `markdown-it` | **Dual-Engine: `marked` (default) + `micromark`** | | **Parsing Strategy** | Full Re-parse | Full Re-parse | **Incremental Parsing** | | **Parsing Complexity** | O(N²) | O(N²) | **O(N)** | | **Boundary Handling** | **Regex Interception** | **Regex Patching** | **State-based Boundary Detection** | | **Typewriter Effect** | Text Layer (String slicing) | Component Layer (``) | **AST Node Layer** (Incremental Append) | | **Animation Perf** | Degrades with content length | O(1) per mounting | **Constant CPU usage per tick** | | **Big Doc Optimization** | None | **Virtualization + Batching** | **Stable IDs + Selective Rendering** | | **Plugin Ecosystem** | Limited | markdown-it plugins | **micromark + mdast + marked extensions** | | **Framework Support** | React | Vue | **Vue + React + Svelte (Shared Core)** | *** ## Deep Dive ### 1. Incremental vs Full Parsing For a 10,000-character document with 10 new characters added: * **Full Parsing**: The parser must scan all 10,010 characters. Processing time grows exponentially with conversation length. * **Incremental Parsing**: `IncremarkParser` identifies the first 10,000 characters as belonging to "stable blocks" and only performs limited contextual analysis on the new 10 characters. ### 2. Animation Precision * **Text Layer (Ant Design X)**: The animator doesn't know if a character belongs to a heading or a code block; it just slices a string. This can cause structural "jumping" during high-frequency updates. * **Component Layer (MarkStream Vue)**: Animation is often restricted to paragraph or block-level fade-ins, making it hard to achieve a smooth, character-by-character "typewriter" feel. * **AST Layer (Incremark)**: `BlockTransformer` is aware of the AST structure. It knows exactly where the new text nodes are. By maintaining a `TextChunk` queue within nodes, it enables smooth character-level animation while maintaining structural integrity (e.g., ensuring a `**bold**` block never crashes the renderer mid-animation). *** ## Conclusion & Best Use Cases ### **Ant Design X** (The Design System Choice) * **Best For**: Rapidly building AI chat interfaces for web applications already using Ant Design. Its regex repair strategy is very reliable for common Markdown edge cases in shorter chats. ### **MarkStream Vue** (The Document Viewer) * **Best For**: Vue applications that need to display extremely large AI responses or long-form documents where virtualization (scrolling performance) is the priority. ### **Incremark** (The High-Performance Standard) * **Best For**: Corporate-grade AI applications with long context windows (100k+ tokens), multi-framework teams, or any scenario where the smoothest possible "human-like" typing animation is required without sacrificing battery life or performance. *** ## Benchmark Results We conducted extensive benchmarks across 38 real-world markdown documents (6,484 lines, 128.55 KB total). > 📊 See the [complete benchmark data](/advanced/engines#complete-benchmark-data) for detailed results of all 38 test files. ### Overall Performance (Averages) | Comparison | Average Advantage | |------------|-------------------| | vs Streamdown | ~**6.1x faster** | | vs ant-design-x | ~**7.2x faster** | | vs markstream-vue | ~**28.3x faster** | > ⚠ These are averages across all test scenarios. Individual performance varies by content type. ### Scaling with Document Size The larger the document, the greater Incremark's advantage — O(n) vs O(n²): | File | Lines | Size | Incremark | ant-design-x | Advantage | |------|-------|------|-----------|--------------|-----------| | introduction.md | 34 | 1.57 KB | 5.6 ms | 12.8 ms | **2.3x** | | comparison.md | 109 | 5.39 KB | 20.5 ms | 85.2 ms | **4.1x** | | BLOCK\_TRANSFORMER.md | 489 | 9.24 KB | 75.7 ms | 619.9 ms | **8.2x** | | test-md-01.md | 916 | 17.67 KB | 87.7 ms | 1656.9 ms | **18.9x** 🚀 | ### Understanding Performance Differences #### Why Incremark is Sometimes "Slower" vs Streamdown In some benchmarks, Incremark appears slower than Streamdown: | File | Incremark | Streamdown | Reason | |------|-----------|------------|--------| | footnotes.md | 1.7 ms | 0.2 ms | Streamdown **doesn't support footnotes** | | FOOTNOTE\_FIX\_SUMMARY.md | 22.7 ms | 0.5 ms | Same — skips footnote parsing | **This is a feature difference, not a performance issue:** * Streamdown skips unsupported syntax → appears faster * Incremark fully parses footnotes, math, containers → does more work #### Incremark's Enhanced Features Incremark extends Marked with custom extensions that Streamdown doesn't support: | Feature | Incremark | Streamdown | |---------|-----------|------------| | **Footnotes** | ✅ Full GFM footnotes | ❌ Not supported | | **Math Blocks** | ✅ `$...$` and `$$...$$` | ⚠ Partial | | **Custom Containers** | ✅ `:::tip`, `:::warning` | ❌ Not supported | | **Inline HTML Parsing** | ✅ Full HTML tree | ⚠ Basic | #### Where Incremark Truly Shines For standard markdown (no footnotes), Incremark consistently outperforms: | File | Lines | Incremark | Streamdown | vs Streamdown | |------|-------|-----------|------------|---------------| | concepts.md | 91 | 12.0 ms | 50.5 ms | **4.2x** | | complex-html-examples.md | 147 | 9.0 ms | 58.8 ms | **6.6x** | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 208.4 ms | **10.9x** | | test-md-01.md | 916 | 87.7 ms | 1441.1 ms | **16.4x** | ### Why Incremark Excels 1. **Incremental Parsing O(n)**: Each append only processes new content 2. **Linear Scaling**: Advantage grows with document size 3. **Streaming-Optimized**: Microsecond-level chunk processing 4. **Feature-Rich**: Supports footnotes, math, containers without sacrificing speed ### Ideal Use Cases ✅ **Incremark shines in:** * AI chat with streaming output (Claude, ChatGPT, etc.) * Real-time markdown editors * Large document incremental rendering * Long-running conversations with 100k+ tokens * Content requiring footnotes, math, or custom containers ⚠ **Consider alternatives for:** * One-time static markdown rendering * Very small files (<500 characters) --- --- url: /guide/concepts.md --- # Core Concepts Understanding how Incremark works will help you build high-performance, flicker-free AI chat applications. ## Dual-Engine Architecture Incremark supports two parsing engines, allowing you to choose based on your needs: | Engine | Characteristics | Best For | |--------|----------------|----------| | **marked** (default) | Extremely fast, streaming-optimized | Real-time AI chat, performance-critical scenarios | | **micromark** | CommonMark compliant, rich plugin ecosystem | Complex extensions, strict spec compliance | Both engines share the same incremental parsing layer and produce identical mdast output, ensuring consistent behavior regardless of which engine you choose. ## Incremental Parsing Flow Traditional Markdown parsers (like `marked` or `markdown-it`) are designed for static documents. In a streaming context, they must re-parse the entire document from scratch every time a new character is received. **Incremark** employs a completely different "Incremental Parsing" strategy: ```mermaid graph TD Stream["Markdown Stream"] --> Buffer["Line Buffer"] Buffer --> Boundary["Boundary Detection"] subgraph Engine ["Incremental Engine"] Boundary -- "Stable Boundary Detected" --> Completed["Completed Block (Cached)"] Boundary -- "Inside Unstable Region" --> Pending["Pending Block"] end Completed --> Cache["AST Cache (Mdast)"] Pending --> ReParse["Local Re-parse (Current Block Only)"] Cache --> FinalAST["Full AST (Root)"] ReParse --> FinalAST FinalAST --> Transformer["BlockTransformer (Animation handling)"] ``` ## Block Lifecycle In Incremark, every top-level element (heading, paragraph, code block, etc.) is treated as an independent **Block**. They go through a lifecycle from "uncertain" to "stable": | State | Description | Handling Strategy | | :--- | :--- | :--- | | **Pending** | Currently streaming; content and type may change at any time. | Every time new content arrives, a micro-parse is performed only on the text segment for this block. | | **Completed** | Confirmed as finished; subsequent input will not affect this block. | **Persistent Cache**. Unless the stream is reset, it is no longer involved in parsing or re-rendering. | > \[!TIP] > **Why do we need a Pending state?** > In Markdown, the prefix determines the type. For example, when `#` is input, it could be a heading or just text. The type is only truly determined when a space or newline is received. ## Boundary Detection Rules Incremark uses heuristic rules to determine when a block can transition from `Pending` to `Completed`: ### 1. Simple Block Boundaries * **Empty Line**: The natural end of a paragraph. * **New Heading / Thematic Break**: The appearance of a new block implies the end of the previous non-container block. ### 2. Fenced Block Boundaries * **Code Block (\`\`\`)**: Must detect a matching closing fence. Until the closing fence appears, the entire code block remains `Pending`. * **Custom Container (:::)**: Same as above; supports nested detection. ### 3. Nested Block Boundaries * **Lists and Blockquotes**: The parser continuously tracks the current indentation level and blockquote depth. When a new line's indentation retreats or the quote marker disappears, the previous block is determined to be finished. ## Context Tracking To accurately identify boundaries during the streaming process, the parser maintains a lightweight state machine: ```ts interface BlockContext { inFencedCode: boolean; // Processing a code block inContainer: boolean; // Processing a custom container listStack: ListInfo[]; // Tracking nested list state blockquoteDepth: number; // Tracking blockquote depth } ``` ## Performance Analysis Thanks to the incremental mechanism, Incremark's performance is almost independent of the total document length and only linearly related to the current chunk size. | Dimension | Traditional Full Parsing | Incremark Incremental Parsing | | :--- | :--- | :--- | | **Incremental Complexity** | O(N) | **O(K)** | | **Total Parsing Complexity** | O(N²) | **O(N)** | | **Memory Overhead** | High (Repeated object creation) | **Low (Incremental AST reuse)** | | **UI Responsiveness** | Performance degrades as N grows | **Maintains 60fps smooth performance** | *Note: N is total document length, K is current chunk size.* ## Typewriter Effect (BlockTransformer) After the AST is parsed, the `BlockTransformer` acts as a filtering layer before rendering. It converts the "instant results" of parsing into a "progressive process": 1. **Node Tracking**: Keeps track of which characters have already been "played." 2. **TextChunk Wrapping**: Wraps newly added text nodes into `TextChunk`, allowing the rendering layer to implement fade-in animations. 3. **Smart Skipping**: It can strategically skip animations if the user requests immediate display or for non-text nodes (like images). --- --- url: /features/custom-codeblocks.md --- # Custom Code Blocks ## Overview Incremark provides a layered architecture for code block customization: 1. **customCodeBlocks**: Language-specific custom components (highest priority) 2. **Built-in Mermaid**: Automatic Mermaid diagram support 3. **components\['code']**: Custom default code rendering 4. **Default**: Built-in Shiki syntax highlighting ## Custom Code Block Rendering Useful for specialized rendering like echarts, custom diagrams, etc. ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function EchartsBlock({ codeStr, lang, completed, takeOver }) { // codeStr is code content // lang is language identifier // completed indicates if the block is complete return
{codeStr}
} const customCodeBlocks = { echarts: EchartsBlock } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' function EchartsBlock(props: { codeStr: string lang: string completed: boolean takeOver: boolean }) { return
{props.codeStr}
} const customCodeBlocks = { echarts: EchartsBlock } ``` ::: ## Custom Code Block Props When creating a custom code block component, your component will receive these props: | Prop | Type | Description | |---|---|---| | `codeStr` | `string` | The code content | | `lang` | `string` | Language identifier | | `completed` | `boolean` | Whether the block is complete | | `takeOver` | `boolean` | Whether takeOver mode is enabled | ## codeBlockConfigs | Option | Type | Default | Description | |---|---|---|---| | `takeOver` | `boolean` | `false` | Take over rendering while pending | ## Built-in Mermaid Support ::: tip Mermaid diagrams are supported out of the box! No configuration needed. ::: Incremark automatically renders Mermaid diagrams with: * Debounced rendering for streaming input * Preview/source toggle * Copy functionality * Dark theme by default ```markdown \`\`\`mermaid graph TD A[Start] --> B{Is it working?} B -->|Yes| C[Great!] B -->|No| D[Debug] D --> A \`\`\` ``` If you want to override the built-in Mermaid rendering, use `customCodeBlocks`: ::: code-group ```vue [Vue] ``` ::: ## Comparison with components\['code'] | Feature | customCodeBlocks | components\['code'] | |---|---|---| | Scope | Specific languages | All code blocks (fallback) | | Priority | Highest | Lower than customCodeBlocks and Mermaid | | Use case | Specialized rendering (echarts, diagrams) | Custom syntax highlighting theme | | Props | `codeStr`, `lang`, `completed`, `takeOver` | `node`, `theme`, `fallbackTheme`, `disableHighlight` | See [Custom Components](/features/custom-components) for more details on `components['code']`. --- --- url: /features/custom-components.md --- # Custom Components ## Custom Node Rendering ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function CustomHeading({ node, children }) { const Tag = `h${node.depth}` as keyof JSX.IntrinsicElements return {children} } const components = { heading: CustomHeading } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' import CustomHeading from './CustomHeading' const components = { heading: CustomHeading } ``` ::: ## Component Types | Type | Node | |---|---| | `heading` | Headings h1-h6 | | `paragraph` | Paragraph | | `code` | Code block (default rendering only) | | `list` | List | | `listItem` | List item | | `table` | Table | | `blockquote` | Blockquote | | `thematicBreak` | Divider | | `image` | Image | | `link` | Link | | `inlineCode` | Inline code | ## Code Component Behavior ::: tip Important When customizing the `code` component, it only replaces the **default code block rendering**. The built-in Mermaid support and `customCodeBlocks` logic are preserved. ::: The code block rendering follows this priority: 1. **customCodeBlocks**: Language-specific custom components (e.g., `echarts`, `mermaid`) 2. **Built-in Mermaid**: Automatic Mermaid diagram rendering 3. **components\['code']**: Custom default code block (if provided) 4. **Default**: Built-in syntax highlighting with Shiki This means: * If you set `components: { code: MyCodeBlock }`, it only affects regular code blocks * Mermaid diagrams will still use the built-in Mermaid renderer * `customCodeBlocks` configurations take precedence ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function MyCodeBlock({ node }) { return (
      {node.value}
    
) } const components = { code: MyCodeBlock } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' function MyCodeBlock(props: { node: any }) { return (
      {props.node.value}
    
) } const components = { code: MyCodeBlock } ``` ::: ### Custom Code Component Props When creating a custom code component, your component will receive these props: | Prop | Type | Description | |---|---|---| | `node` | `Code` | The code node from mdast | | `theme` | `string` | Shiki theme name | | `fallbackTheme` | `string` | Fallback theme when loading fails | | `disableHighlight` | `boolean` | Whether to disable syntax highlighting | The `node` object contains: * `node.value`: The code content as a string * `node.lang`: The language identifier (e.g., `'typescript'`, `'python'`) * `node.meta`: Optional metadata after the language identifier --- --- url: /features/custom-containers.md --- # Custom Containers ## Markdown Syntax ```markdown ::: warning This is a warning ::: ::: info Title This is an info box ::: ``` ## Defining Container Components ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function WarningContainer({ node, children }) { return (
{node.title || 'Warning'}
{children}
) } const customContainers = { warning: WarningContainer } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' function WarningContainer(props: { node: any; children: any }) { return (
{props.node.title || 'Warning'}
{props.children}
) } const customContainers = { warning: WarningContainer } ``` ::: ## Container Component Props | Prop | Type | Description | |---|---|---| | `node` | `ContainerNode` | Container node | | `node.name` | `string` | Container name (warning, info, etc.) | | `node.title` | `string?` | Container title | | `children` | - | Container content | --- --- url: /examples/custom-stream.md --- # Custom Stream Integration Parsing a raw standard `Response` stream. ## Example ```ts import { IncremarkContent } from '@incremark/react' function App() { const [stream, setStream] = useState(null) function start() { async function* fetchStream() { const response = await fetch('/api/stream') const reader = response.body.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done) break yield decoder.decode(value, { stream: true }) } } setStream(() => fetchStream) } return ( <> ) } ``` --- --- url: /features/devtools.md --- # DevTools Incremark DevTools provides a visual interface for debugging and inspecting incremental markdown rendering. It supports real-time monitoring of parser state, block details, AST structure, and append history. ## Installation ::: code-group ```bash [npm] npm install @incremark/devtools ``` ```bash [pnpm] pnpm add @incremark/devtools ``` ```bash [yarn] yarn add @incremark/devtools ``` ::: ## Basic Usage ### Vue ```vue ``` ### React ```tsx import { createDevTools } from '@incremark/devtools' import { IncremarkContent } from '@incremark/react' import { useEffect, useRef } from 'react' function App() { const devtools = useRef(createDevTools({ locale: 'en-US' // 'en-US' or 'zh-CN' })) useEffect(() => { devtools.current.mount() return () => devtools.current.unmount() }, []) return ( ) } ``` ### Svelte ```svelte ``` ### Solid ```tsx import { createDevTools } from '@incremark/devtools' import { IncremarkContent } from '@incremark/solid' import { onMount, onCleanup } from 'solid-js' const devtools = createDevTools({ locale: 'en-US' // 'en-US' or 'zh-CN' }) onMount(() => { devtools.mount() }) onCleanup(() => { devtools.unmount() }) return ( ) ``` ## Configuration Options ```ts const devtools = createDevTools({ open: false, // Initially open the panel position: 'bottom-right', // Position: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' theme: 'dark', // Theme: 'dark' | 'light' locale: 'en-US' // Locale: 'en-US' | 'zh-CN' }) ``` ## Dynamic Locale Switching You can dynamically change the DevTools language: ```ts import { setLocale } from '@incremark/devtools' // Switch to Chinese setLocale('zh-CN') // Switch to English setLocale('en-US') ``` ## IncremarkContent Props When using DevTools with `IncremarkContent`, you can pass these additional props: | Prop | Type | Default | Description | |------|------|---------|-------------| | `devtools` | `IncremarkDevTools` | - | The devtools instance to register with | | `devtoolsId` | `string` | Auto-generated | Unique identifier for this parser in devtools | | `devtoolsLabel` | `string` | `devtoolsId` | Display label for this parser in devtools | ## Features DevTools provides four main tabs: ### Overview * Total block count * Completed and pending blocks * Character count * Node type distribution * Current streaming status ### Blocks * List of all parsed blocks * Block details (ID, type, status, raw text) * AST node inspection * Real-time status updates ### AST * Complete Abstract Syntax Tree view * Interactive tree structure * Node property inspection ### Timeline * Append history with timestamps * Track incremental updates * Block count changes over time ## Multiple Parsers DevTools supports monitoring multiple parsers simultaneously: ```vue ``` Use the dropdown in DevTools to switch between different parsers. --- --- url: /zh/features/devtools.md --- # DevTools 匀发工具 Incremark DevTools 提䟛了䞀䞪可视化界面甚于调试和检查增量 Markdown 枲染。它支持实时监控解析噚状态、块诊情、AST 结构和远加历史。 ## 安装 ::: code-group ```bash [npm] npm install @incremark/devtools ``` ```bash [pnpm] pnpm add @incremark/devtools ``` ```bash [yarn] yarn add @incremark/devtools ``` ::: ## 基本甚法 ### Vue ```vue ``` ### React ```tsx import { createDevTools } from '@incremark/devtools' import { IncremarkContent } from '@incremark/react' import { useEffect, useRef } from 'react' function App() { const devtools = useRef(createDevTools({ locale: 'zh-CN' // 'en-US' 或 'zh-CN' })) useEffect(() => { devtools.current.mount() return () => devtools.current.unmount() }, []) return ( ) } ``` ### Svelte ```svelte ``` ### Solid ```tsx import { createDevTools } from '@incremark/devtools' import { IncremarkContent } from '@incremark/solid' import { onMount, onCleanup } from 'solid-js' const devtools = createDevTools({ locale: 'zh-CN' // 'en-US' 或 'zh-CN' }) onMount(() => { devtools.mount() }) onCleanup(() => { devtools.unmount() }) return ( ) ``` ## 配眮选项 ```ts const devtools = createDevTools({ open: false, // 初始是吊打匀面板 position: 'bottom-right', // 䜍眮: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left' theme: 'dark', // 䞻题: 'dark' | 'light' locale: 'zh-CN' // 语蚀: 'en-US' | 'zh-CN' }) ``` ## 劚态语蚀切换 悚可以劚态曎改 DevTools 的语蚀 ```ts import { setLocale } from '@incremark/devtools' // 切换到䞭文 setLocale('zh-CN') // 切换到英文 setLocale('en-US') ``` ## IncremarkContent 属性 将 DevTools 侎 `IncremarkContent` 䞀起䜿甚时悚可以䌠递以䞋额倖属性 | 属性 | 类型 | 默讀倌 | 描述 | |------|------|---------|-------------| | `devtools` | `IncremarkDevTools` | - | 芁泚册的 devtools 实䟋 | | `devtoolsId` | `string` | 自劚生成 | 圚 devtools 䞭歀解析噚的唯䞀标识笊 | | `devtoolsLabel` | `string` | `devtoolsId` | 圚 devtools 䞭歀解析噚的星瀺标筟 | ## 功胜特性 DevTools 提䟛四䞪䞻芁选项卡 ### 抂览 * 总块数 * 已完成和埅倄理的块 * 字笊数 * 节点类型分垃 * 圓前流匏倄理状态 ### 块 * 所有已解析块的列衚 * 块诊情ID、类型、状态、原始文本 * AST 节点检查 * 实时状态曎新 ### AST * 完敎的抜象语法树视囟 * 亀互匏树结构 * 节点属性检查 ### 时闎线 * 垊时闎戳的远加历史 * 跟螪增量曎新 * 块数随时闎的变化 ## 倚解析噚支持 DevTools 支持同时监控倚䞪解析噚 ```vue ``` 䜿甚 DevTools 䞭的䞋拉菜单圚䞍同解析噚之闎切换。 --- --- url: /advanced/engines.md --- # Dual-Engine Architecture Incremark features a **dual-engine parsing system** — an important architectural decision we made during development. We want to give users the freedom to choose: find the perfect balance between extreme performance and perfect compatibility for your specific use case. ## Why Dual Engines? During Incremark's development, we faced a core question: **How do we achieve the best performance in streaming AI scenarios?** After extensive research and testing, we discovered: * **Marked** is extremely fast, but doesn't natively support footnotes, math, and other advanced features * **Micromark** has perfect spec compliance and a rich plugin ecosystem, but has a larger bundle size Our decision: **Why not both?** With the dual-engine architecture, users can choose based on their needs: * Performance-sensitive AI chat scenarios → Use the Marked engine * Documents requiring strict spec compliance → Use the Micromark engine ## Engine Overview | Engine | Speed | Features | Bundle Size | Best For | |--------|-------|----------|-------------|----------| | **Marked** (Default) | ⚡⚡⚡⚡⚡ | Standard + Enhanced Extensions | Smaller | Real-time streaming, AI chat | | **Micromark** | ⚡⚡⚡ | Full CommonMark + Plugins | Larger | Complex documents, strict compliance | ## Marked Engine (Default) The **Marked engine** is our default choice, deeply optimized for **streaming AI scenarios**. ### Why Marked as the Default? 1. **Extreme parsing speed**: Marked is one of the fastest Markdown parsers in the JavaScript ecosystem 2. **Battle-tested stability**: Over 10 years of history, validated by countless projects 3. **Easy to extend**: Flexible extension mechanism allows us to add features as needed 4. **Small bundle size**: Benefits frontend tree-shaking optimization ### What We Enhanced for Marked Native Marked is a "good enough" parser focused on standard Markdown syntax, without many advanced features. But in AI scenarios, we often need these features. Therefore, Incremark extends Marked with custom extensions: | Feature | Native Marked | Incremark Enhanced | Description | |---------|---------------|-------------------|-------------| | **Footnotes** | ❌ Not supported | ✅ Full GFM footnotes | `[^1]` references and `[^1]: content` definitions | | **Math Blocks** | ❌ Not supported | ✅ Inline and block math | `$E=mc^2$` and `$$...$$` | | **Custom Containers** | ❌ Not supported | ✅ Directive syntax | `:::tip`, `:::warning`, `:::danger` | | **Inline HTML Parsing** | ⚠ Preserved as-is | ✅ Structured parsing | Parses HTML into manipulable AST nodes | | **Optimistic References** | ❌ Not supported | ✅ Streaming-friendly | Gracefully handles incomplete links/images during streaming | | **Footnote Definition Blocks** | ❌ Not supported | ✅ Multi-line content | Supports complex footnotes with code blocks, lists, etc. | > 💡 These extensions are carefully designed for AI scenarios. They provide full functionality while minimizing performance overhead. ### Usage The Marked engine is the **default**, so you don't need any special configuration: ```vue ``` ### Enable/Disable Specific Features ```vue ``` ## Micromark Engine The **Micromark engine** is the choice for perfect spec compliance. ### Why Offer Micromark? While the Marked engine satisfies most scenarios, some users may have stricter requirements: 1. **Strict CommonMark compliance**: Micromark is currently the most spec-compliant parser 2. **Rich plugin ecosystem**: GFM, Math, Directive plugins are all community-polished 3. **Precise position information**: AST nodes include accurate line/column positions for error locating 4. **Better edge case handling**: More stable in complex nested scenarios ### Usage To use the Micromark engine, you need to import `MicromarkAstBuilder` and pass it via `astBuilder` option: ```ts // In your composable or setup import { createIncremarkParser } from '@incremark/core' import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true, math: true }) ``` > **Note**: The `IncremarkContent` component currently uses the Marked engine by default. To use Micromark with the component, you would need to use `useIncremark` directly with a custom parser. ### When Should You Use Micromark? * Your content includes complex nested structures * You need to handle edge cases that Marked can't parse correctly * Your application has strict CommonMark compliance requirements * You need Micromark plugins beyond our built-in extensions ## Complete Benchmark Data We benchmarked 38 real Markdown files. Here are the complete results: ### Test Environment * **Test files**: 38 files, 6,484 lines total, 128.55 KB * **Test method**: Simulated streaming input, character-by-character append * **Compared solutions**: Streamdown, markstream-vue, ant-design-x ### Full Test Results | Filename | Lines | Size(KB) | Incremark | Streamdown | markstream | ant-design-x | vs Streamdown | vs markstream | vs ant-design-x | |----------|-------|----------|-----------|------------|------------|--------------|---------------|---------------|-----------------| | test-footnotes-simple.md | 15 | 0.09 | 0.3 ms | 0.0 ms | 1.4 ms | 0.2 ms | 0.1x | 4.7x | 0.6x | | simple-paragraphs.md | 16 | 0.41 | 0.9 ms | 0.9 ms | 5.9 ms | 1.0 ms | 1.1x | 6.7x | 1.2x | | test-footnotes-multiline.md | 21 | 0.18 | 0.6 ms | 0.0 ms | 2.2 ms | 0.4 ms | 0.1x | 3.5x | 0.6x | | test-footnotes-edge-cases.md | 27 | 0.25 | 0.8 ms | 0.0 ms | 4.2 ms | 1.2 ms | 0.0x | 5.3x | 1.5x | | test-footnotes-complex.md | 28 | 0.24 | 2.1 ms | 0.0 ms | 4.8 ms | 1.0 ms | 0.0x | 2.3x | 0.5x | | introduction.md | 34 | 1.57 | 5.6 ms | 12.6 ms | 75.6 ms | 12.8 ms | 2.2x | 13.4x | 2.3x | | devtools.md | 51 | 0.92 | 1.2 ms | 0.9 ms | 6.1 ms | 1.1 ms | 0.8x | 5.0x | 0.9x | | footnotes.md | 52 | 0.94 | 1.7 ms | 0.2 ms | 10.6 ms | 1.9 ms | 0.1x | 6.3x | 1.2x | | html-elements.md | 55 | 1.02 | 1.6 ms | 2.2 ms | 12.6 ms | 2.8 ms | 1.4x | 7.8x | 1.7x | | themes.md | 58 | 0.96 | 1.9 ms | 1.3 ms | 8.6 ms | 1.8 ms | 0.7x | 4.4x | 0.9x | | test-footnotes-comprehensive.md | 63 | 0.66 | 5.6 ms | 0.1 ms | 25.8 ms | 7.7 ms | 0.0x | 4.6x | 1.4x | | auto-scroll.md | 72 | 1.68 | 3.9 ms | 3.5 ms | 39.9 ms | 4.9 ms | 0.9x | 10.1x | 1.2x | | custom-codeblocks.md | 72 | 1.44 | 3.4 ms | 2.0 ms | 14.9 ms | 2.5 ms | 0.6x | 4.4x | 0.7x | | custom-components.md | 73 | 1.40 | 4.0 ms | 2.0 ms | 32.7 ms | 2.9 ms | 0.5x | 8.1x | 0.7x | | custom-containers.md | 88 | 1.67 | 4.2 ms | 2.4 ms | 18.1 ms | 3.1 ms | 0.6x | 4.3x | 0.7x | | typewriter.md | 88 | 1.89 | 5.6 ms | 4.1 ms | 35.0 ms | 4.9 ms | 0.7x | 6.2x | 0.9x | | concepts.md | 91 | 4.29 | 12.0 ms | 50.5 ms | 381.9 ms | 53.6 ms | 4.2x | 31.9x | 4.5x | | INLINE\_CODE\_UPDATE.md | 94 | 1.66 | 4.7 ms | 17.2 ms | 60.9 ms | 15.6 ms | 3.7x | 12.9x | 3.3x | | comparison.md | 109 | 5.39 | 20.5 ms | 74.0 ms | 552.2 ms | 85.2 ms | 3.6x | 26.9x | 4.1x | | basic-usage.md | 130 | 3.04 | 8.5 ms | 12.3 ms | 74.1 ms | 14.1 ms | 1.4x | 8.7x | 1.7x | | CODE\_BACKGROUND\_SEPARATION.md | 131 | 2.83 | 8.7 ms | 28.8 ms | 153.6 ms | 31.3 ms | 3.3x | 17.6x | 3.6x | | P2\_SUMMARY.md | 138 | 2.61 | 8.3 ms | 38.4 ms | 157.2 ms | 41.9 ms | 4.6x | 18.9x | 5.0x | | quick-start.md | 146 | 3.04 | 7.3 ms | 7.3 ms | 64.2 ms | 9.6 ms | 1.0x | 8.8x | 1.3x | | complex-html-examples.md | 147 | 3.99 | 9.0 ms | 58.8 ms | 279.3 ms | 57.2 ms | 6.6x | 31.1x | 6.4x | | CODE\_COLOR\_SEPARATION.md | 162 | 3.51 | 10.0 ms | 32.8 ms | 191.1 ms | 36.9 ms | 3.3x | 19.1x | 3.7x | | P0\_OPTIMIZATION\_REPORT.md | 168 | 3.53 | 10.1 ms | 56.2 ms | 228.0 ms | 58.1 ms | 5.6x | 22.6x | 5.8x | | COLOR\_SYSTEM\_REFACTOR.md | 169 | 3.78 | 18.5 ms | 64.0 ms | 355.5 ms | 69.1 ms | 3.5x | 19.2x | 3.7x | | FOOTNOTE\_TEST\_GUIDE.md | 219 | 2.87 | 12.3 ms | 0.2 ms | 167.6 ms | 45.0 ms | 0.0x | 13.7x | 3.7x | | P2\_COLORS\_PACKAGE\_REPORT.md | 226 | 4.10 | 11.4 ms | 77.9 ms | 311.6 ms | 80.5 ms | 6.8x | 27.2x | 7.0x | | FOOTNOTE\_FIX\_SUMMARY.md | 236 | 3.93 | 22.7 ms | 0.5 ms | 535.0 ms | 120.8 ms | 0.0x | 23.6x | 5.3x | | BASE\_COLORS\_SYSTEM.md | 259 | 4.47 | 35.8 ms | 43.0 ms | 191.8 ms | 43.4 ms | 1.2x | 5.4x | 1.2x | | OPTIMIZATION\_COMPARISON.md | 270 | 5.42 | 17.8 ms | 52.3 ms | 366.1 ms | 61.9 ms | 2.9x | 20.6x | 3.5x | | P1\_OPTIMIZATION\_REPORT.md | 327 | 5.63 | 20.7 ms | 106.8 ms | 433.8 ms | 114.8 ms | 5.2x | 21.0x | 5.5x | | OPTIMIZATION\_PLAN.md | 371 | 6.89 | 33.1 ms | 67.6 ms | 372.1 ms | 76.7 ms | 2.0x | 11.2x | 2.3x | | OPTIMIZATION\_SUMMARY.md | 391 | 6.24 | 19.1 ms | 208.4 ms | 980.6 ms | 217.8 ms | 10.9x | 51.3x | 11.4x | | P1.5\_COLOR\_SYSTEM\_REPORT.md | 482 | 9.12 | 22.0 ms | 145.5 ms | 789.8 ms | 168.2 ms | 6.6x | 35.9x | 7.7x | | BLOCK\_TRANSFORMER\_ANALYSIS.md | 489 | 9.24 | 75.7 ms | 574.3 ms | 1984.1 ms | 619.9 ms | 7.6x | 26.2x | 8.2x | | test-md-01.md | 916 | 17.67 | 87.7 ms | 1441.1 ms | 5754.7 ms | 1656.9 ms | 16.4x | 65.6x | 18.9x | | **【Total】** | **6484** | **128.55** | **519.4 ms** | **3190.3 ms** | **14683.9 ms** | **3728.6 ms** | **6.1x** | **28.3x** | **7.2x** | ### How to Interpret This Data #### We're Honest: Incremark is Slower in Some Scenarios You may notice that for `test-footnotes-*.md` and `FOOTNOTE_*.md` files, Incremark is much slower than Streamdown (0.0x - 0.1x). **The reason is simple: Streamdown doesn't support footnote syntax.** When Streamdown encounters `[^1]` footnote references, it simply skips them. Meanwhile, Incremark: 1. Recognizes footnote references 2. Parses footnote definition blocks (which may contain multi-line content, code blocks, lists, etc.) 3. Establishes reference relationships 4. Generates correct AST structure This isn't a performance issue — it's a **feature difference**. We believe complete footnote support is crucial for AI scenarios, so we chose to implement it. #### Where's the Real Performance Advantage? Excluding footnote-related files, look at standard Markdown content performance: | File | Lines | Incremark | Streamdown | Advantage | |------|-------|-----------|------------|-----------| | concepts.md | 91 | 12.0 ms | 50.5 ms | **4.2x** | | comparison.md | 109 | 20.5 ms | 74.0 ms | **3.6x** | | complex-html-examples.md | 147 | 9.0 ms | 58.8 ms | **6.6x** | | P0\_OPTIMIZATION\_REPORT.md | 168 | 10.1 ms | 56.2 ms | **5.6x** | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 208.4 ms | **10.9x** | | test-md-01.md | 916 | 87.7 ms | 1441.1 ms | **16.4x** | **Conclusion**: For standard Markdown content, the larger the document, the more pronounced Incremark's advantage. #### Why Such a Gap? This is the direct result of **O(n) vs O(n²)** algorithmic complexity. Traditional parsers (Streamdown, ant-design-x, markstream-vue) **re-parse the entire document** on every new chunk: ``` Chunk 1: Parse 100 chars Chunk 2: Parse 200 chars (100 old + 100 new) Chunk 3: Parse 300 chars (200 old + 100 new) ... Chunk 100: Parse 10,000 chars ``` Total work: `100 + 200 + 300 + ... + 10000 = 5,050,000` character operations **Incremark's incremental parsing** only processes new content: ``` Chunk 1: Parse 100 chars → cache stable blocks Chunk 2: Parse only ~100 new chars Chunk 3: Parse only ~100 new chars ... Chunk 100: Parse only ~100 new chars ``` Total work: `100 × 100 = 10,000` character operations That's a **500x difference**. This is why an 18KB document can be 16x+ faster. ## Feature Parity We strive to keep both engines functionally consistent: | Feature | Marked Engine | Micromark Engine | |---------|---------------|------------------| | GFM (Tables, Strikethrough, Autolinks) | ✅ | ✅ | | Math Blocks (`$...$` and `$$...$$`) | ✅ | ✅ | | Custom Containers (`:::tip`, etc.) | ✅ | ✅ | | HTML Element Parsing | ✅ | ✅ | | Footnotes | ✅ | ✅ | | Typewriter Animation | ✅ | ✅ | | Incremental Updates | ✅ | ✅ | ## Switching Engines Engine selection is done at **initialization time**, not runtime. This is by design for tree-shaking optimization. ### Why Not Runtime Switching? To ensure optimal bundle size: * Default import only includes the `marked` engine * `micromark` engine is imported separately when needed * This allows bundlers to tree-shake unused engines ### How to Switch Engines ```vue ``` ### Using Micromark Engine To use micromark, import `MicromarkAstBuilder` from the separate engine entry: ```ts import { createIncremarkParser } from '@incremark/core' import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' // Create parser with micromark engine const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true, math: true }) ``` > ⚠ **Tree-shaking Note**: Importing from `@incremark/core/engines/micromark` only adds micromark to your bundle. The default import keeps only marked. ## Extending Engines Both engines support custom extensions. See the [Extensions Guide](/advanced/extensions) for details. ```ts // Custom marked extension example import { createCustomExtension } from '@incremark/core' const myExtension = createCustomExtension({ name: 'myPlugin', // ... extension config }) ``` ## Summary and Recommendations | Aspect | Marked | Micromark | |--------|--------|-----------| | Parsing Speed | ⚡⚡⚡⚡⚡ | ⚡⚡⚡ | | Bundle Size | 📊 Smaller | 📊 Larger | | CommonMark Compliance | ✅ Good | ✅ Perfect | | Built-in Extensions | ✅ Footnotes, Math, Containers | ✅ Via plugins | | Plugin Ecosystem | 🔧 Growing | 🔧 Mature | | Recommended For | Streaming AI, Real-time rendering | Static documents, Strict compliance | **Our Recommendations**: 1. **Most scenarios**: Use the default Marked engine — it's already great 2. **Parsing issues**: If Marked doesn't handle certain edge cases well, try switching to Micromark 3. **Extreme performance needs**: Marked engine is your best choice 4. **Strict compliance needs**: Micromark engine is more suitable We'll continue optimizing both engines to ensure they provide the best experience for you. --- --- url: /advanced/extensions.md --- # Extensions Incremark's dual-engine architecture provides flexible extension mechanisms for both `micromark` and `marked` engines. ## Engine Selection Choose the appropriate engine based on your extension needs: | Engine | Extension Type | Best For | |--------|---------------|----------| | `micromark` | micromark + mdast extensions | Rich ecosystem, CommonMark compliance | | `marked` | Custom token transformers | Maximum performance, simple extensions | ## Micromark Extensions When using the `micromark` engine, you can leverage the rich ecosystem of existing extensions. ### Syntax Extensions Use `micromark` extensions to support new syntax: ```vue ``` ### AST Extensions Use `mdast-util-from-markdown` extensions to transform syntax to AST nodes: ```ts import { gfmTableFromMarkdown } from 'mdast-util-gfm-table' import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, extensions: [gfmTable()], mdastExtensions: [gfmTableFromMarkdown()] }) ``` ### Common Extension Packages | Package | Description | |---------|-------------| | `micromark-extension-gfm` | Full GFM support | | `micromark-extension-math` | Math formulas | | `micromark-extension-directive` | Custom containers | | `micromark-extension-frontmatter` | YAML frontmatter | ## Marked Extensions The `marked` engine uses a custom extension system. Incremark has already extended `marked` with support for: * **Footnotes**: `[^1]` references and `[^1]: content` definitions * **Math**: `$inline$` and `$$block$$` formulas * **Custom Containers**: `:::type` syntax * **Inline HTML**: Structured HTML element parsing ### Custom Token Transformers For the `marked` engine, you can provide custom token transformers: ```ts import type { BlockTokenTransformer, InlineTokenTransformer } from '@incremark/core' // Custom block transformer const myBlockTransformer: BlockTokenTransformer = (token, ctx) => { if (token.type === 'myCustomBlock') { return { type: 'paragraph', children: [{ type: 'text', value: token.raw }] } } return null } // For marked engine (default), use customBlockTransformers const parser = createIncremarkParser({ // marked is default, no astBuilder needed customBlockTransformers: { myCustomBlock: myBlockTransformer } }) ``` ### Built-in Transformers You can access and extend the built-in transformers: ```ts import { getBuiltinBlockTransformers, getBuiltinInlineTransformers } from '@incremark/core' // Get all built-in transformers const blockTransformers = getBuiltinBlockTransformers() const inlineTransformers = getBuiltinInlineTransformers() // Override specific transformer const customTransformers = { ...blockTransformers, code: (token, ctx) => { // Custom code block handling return { type: 'code', value: token.text, lang: token.lang } } } ``` ## UI-Level Extensions Beyond parser extensions, Incremark provides UI-level customization: ### Custom Components Replace default rendering for any node type: ```vue ``` ### Custom Code Blocks Handle specific code languages with custom components: ```vue ``` ### Custom Containers Render `:::type` containers with custom components: ```vue ``` ## Extension Best Practices 1. **Choose the right engine**: Use `micromark` for complex syntax extensions, `marked` for performance-critical scenarios. 2. **Leverage existing packages**: The micromark ecosystem has many well-tested extensions. 3. **UI-level first**: For visual customization, prefer UI-level extensions (custom components) over parser extensions. 4. **Test thoroughly**: Custom extensions can affect parsing behavior across different markdown inputs. --- --- url: /features/footnotes.md --- # Footnotes Incremark supports GFM footnotes out of the box. ## Usage Enable the `gfm` option in your configuration. ```markdown Here is a footnote reference[^1]. [^1]: This is the footnote definition. ``` ## Configuration ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' ``` ```svelte [Svelte] ``` ::: ## Rendering Footnotes are automatically collected and rendered at the bottom of the content. You can customize the look using CSS or by overriding the `footnoteDefinition` component. --- --- url: /features/html-elements.md --- # HTML Elements Incremark can parse and render raw HTML fragments embedded in Markdown. ## Usage Enable the `htmlTree` option. ```markdown This is bold and this is red.

Block HTML

Content inside HTML block

``` ## Configuration ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' ``` ```svelte [Svelte] ``` ::: ## Security Warning ⚠ **XSS Risk**: Enabling `htmlTree` allows rendering of arbitrary HTML. Ensure that the content source is trusted or sanitized before passing it to Incremark. --- --- url: /zh/features/html-elements.md --- # HTML 元玠 Incremark 可以解析和枲染嵌入圚 Markdown 䞭的原始 HTML 片段。 ## 甚法 启甚 `htmlTree` 选项。 ```markdown 这是 粗䜓 这是 红色文本。

块级 HTML

HTML 块内的内容

``` ## 配眮 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' ``` ```svelte [Svelte] ``` ::: ## 安党譊告 ⚠ **XSS 风险**启甚 `htmlTree` 允讞枲染任意 HTML。圚将内容䌠递给 Incremark 之前请确保内容来源可信或已净化。 --- --- url: /features/i18n.md --- # Internationalization & Accessibility Incremark provides built-in internationalization (i18n) and accessibility (a11y) support, ensuring components work correctly across different languages and are screen reader friendly. ## Using ConfigProvider `ConfigProvider` is used to provide global i18n configuration: ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, ConfigProvider, zhCN } from '@incremark/react' ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent, ConfigProvider, zhCN } from '@incremark/solid' ``` ::: ## Built-in Locales Incremark includes the following built-in locales: | Locale | Language | |--------|----------| | `en` | English (default) | | `zhCN` | Simplified Chinese | ```ts import { en, zhCN } from '@incremark/vue' // or import { en, zhCN } from '@incremark/react' // or import { en, zhCN } from '@incremark/svelte' // or import { en, zhCN } from '@incremark/solid' ``` ## Custom Locales You can create custom locales to support other languages: ```ts import type { IncremarkLocale } from '@incremark/vue' const jaJP: IncremarkLocale = { code: { copy: 'コヌドをコピヌ', copied: 'コピヌしたした' }, mermaid: { copy: 'コヌドをコピヌ', copied: 'コピヌしたした', viewSource: '゜ヌスコヌドを衚瀺', preview: 'プレビュヌ' } } ``` ## Accessibility Support Incremark's UI components follow WAI-ARIA standards and provide comprehensive accessibility support: ### Code Blocks * Copy buttons use `aria-label` for clear action descriptions * Button state changes (e.g., after copying) update the `aria-label` * Language labels are clearly readable ```html ``` ### Mermaid Diagrams * Toggle buttons (source code/preview) use `aria-label` * Chart containers provide appropriate semantic labels ## Combined Usage `ConfigProvider` can be combined with `ThemeProvider`: ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, ConfigProvider, ThemeProvider, zhCN } from '@incremark/react' ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent, ConfigProvider, ThemeProvider, zhCN } from '@incremark/solid' ``` ::: ## Dynamic Locale Switching Locales can be switched dynamically at runtime: ::: code-group ```vue [Vue] ``` ```tsx [React] import { useState, useMemo } from 'react' import { ConfigProvider, en, zhCN } from '@incremark/react' function App() { const [lang, setLang] = useState('en') const locale = useMemo(() => lang === 'zh' ? zhCN : en, [lang]) return ( <> ) } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal, Index } from 'solid-js' import { ConfigProvider, en, zhCN } from '@incremark/solid' function App() { const [lang, setLang] = createSignal('en') const locale = () => lang() === 'zh' ? zhCN : en const [key, setKey] = createSignal(0) function toggleLocale() { setLang(l => l === 'en' ? 'zh' : 'en') setKey(k => k + 1) } return ( <> {() => ( )} ) } ``` ::: ## Locale Type Definition ```ts interface IncremarkLocale { /** Code block translations */ code: { /** Copy code button text */ copy: string /** Text shown after copying */ copied: string } /** Mermaid diagram translations */ mermaid: { /** Copy code button text */ copy: string /** Text shown after copying */ copied: string /** View source code button text */ viewSource: string /** Preview diagram button text */ preview: string } } ``` --- --- url: /guide/introduction.md --- # Introduction **Incremark** is a markdown renderer designed for the AI era. It prioritizes **streaming performance**, **incremental updates**, and **smooth visual effects**. ## Why Incremark? With the rise of LLMs (Large Language Models), applications are increasingly displaying streaming text. Traditional markdown parsers were built for static documents, not for text that updates 50 times a second. This mismatch leads to: * High CPU usage on long responses. * Janky scrolling and rendering. * Difficulty implementing "Typewriter" effects without breaking markdown syntax. **Incremark** rethinks markdown rendering as a stream processing problem. ## Key Features * ⚡ **Extreme Performance**: Average ~6x faster than Streamdown, ~7x faster than ant-design-x, ~28x faster than markstream-vue. * 🔄 **Dual-Engine Architecture**: Marked with enhanced extensions for speed, or Micromark for strict CommonMark compliance. * 🚀 **O(n) Incremental Parsing**: Only parse what's new — 18KB document is 19x faster than traditional parsers. * ⌚ **Built-in Typewriter**: Smooth character-by-character reveals that respect markdown structure. * 🧩 **Framework Agnostic**: Core logic is shared; connectors for Vue, React, and Svelte. * 🎚 **Themable**: Tailored for modern, dark-mode-first interfaces. * 🛠 **DevTools**: Inspect the parsing process in real-time. ## Ready to Start? Check out the [Quick Start](/guide/quick-start) to integrate it into your app in minutes. ## AI Friendliness Incremark is designed for AI, and our documentation is too. We provide structured versions of our docs for better ingestion by LLMs: * [llms.txt](/llms.txt): A concise index of our documentation. * [llms-full.txt](/llms-full.txt): The entire documentation in a single file, perfect for providing context to Claude, Cursor, or ChatGPT. --- --- url: /examples/openai.md --- # OpenAI Integration Using the `openai` Node.js library. ## Example ```ts import OpenAI from 'openai' import { IncremarkContent } from '@incremark/react' const openai = new OpenAI({ apiKey: 'YOUR_API_KEY', dangerouslyAllowBrowser: true // For client-side demo only }) function App() { const [stream, setStream] = useState(null) async function startChat() { async function* getStream() { const completion = await openai.chat.completions.create({ model: "gpt-4", messages: [{ role: "user", content: "Explain quantum computing" }], stream: true, }) for await (const chunk of completion) { yield chunk.choices[0]?.delta?.content || '' } } setStream(() => getStream) } return ( <> ) } ``` --- --- url: /zh/examples/openai.md --- # OpenAI 集成 䜿甚 `openai` Node.js 库。 ## 瀺䟋 ```ts import OpenAI from 'openai' import { IncremarkContent } from '@incremark/react' const openai = new OpenAI({ apiKey: 'YOUR_API_KEY', dangerouslyAllowBrowser: true // 仅甚于客户端挔瀺 }) function App() { const [stream, setStream] = useState(null) async function startChat() { async function* getStream() { const completion = await openai.chat.completions.create({ model: "gpt-4", messages: [{ role: "user", content: "Explain quantum computing" }], stream: true, }) for await (const chunk of completion) { yield chunk.choices[0]?.delta?.content || '' } } setStream(() => getStream) } return ( <> ) } ``` --- --- url: /guide/quick-start.md --- # Quick Start Get up and running with specific framework integration in 5 minutes. ## Installation ::: code-group ```bash [pnpm] pnpm add @incremark/vue @incremark/theme # OR pnpm add @incremark/react @incremark/theme # OR pnpm add @incremark/svelte @incremark/theme # OR pnpm add @incremark/solid @incremark/theme ``` ```bash [npm] npm install @incremark/vue @incremark/theme # OR npm install @incremark/react @incremark/theme # OR npm install @incremark/svelte @incremark/theme # OR npm install @incremark/solid @incremark/theme ``` ```bash [yarn] yarn add @incremark/vue @incremark/theme # OR yarn add @incremark/react @incremark/theme # OR yarn add @incremark/svelte @incremark/theme # OR yarn add @incremark/solid @incremark/theme ``` ::: ## Basic Usage ::: code-group ```vue [Vue] ``` ```tsx [React] import { useState } from 'react' import { IncremarkContent } from '@incremark/react' import '@incremark/theme/styles.css' // [!code hl] function App() { const [content, setContent] = useState('') const [isFinished, setIsFinished] = useState(false) async function simulateStream() { setContent('') setIsFinished(false) const text = '# Hello\n\nThis is **Incremark**!' const chunks = text.match(/[\s\S]{1,5}/g) || [] for (const chunk of chunks) { setContent(prev => prev + chunk) await new Promise(r => setTimeout(r, 50)) } setIsFinished(true) } return ( <> ) } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent } from '@incremark/solid' import '@incremark/theme/styles.css' // [!code hl] function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) async function simulateStream() { setContent('') setIsFinished(false) const text = '# Hello\n\nThis is **Incremark**!' const chunks = text.match(/[\s\S]{1,5}/g) || [] for (const chunk of chunks) { setContent(prev => prev + chunk) await new Promise(r => setTimeout(r, 50)) } setIsFinished(true) } return ( <> ) } ``` ::: ## Using Stream Mode ```vue ``` ## Math Formulas (Optional) If you need to support math formulas (KaTeX), make sure to also import the KaTeX CSS: ```ts import 'katex/dist/katex.min.css' ``` --- --- url: /features/themes.md --- # Themes ## Using ThemeProvider ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, ThemeProvider } from '@incremark/react' ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent, ThemeProvider } from '@incremark/solid' ``` ::: ## Built-in Themes * `default` - Light theme * `dark` - Dark theme ## Custom Theme ```ts import { type DesignTokens } from '@incremark/vue' const customTheme: Partial = { color: { brand: { primary: '#8b5cf6', primaryHover: '#7c3aed' } } } ``` --- --- url: /features/typewriter.md --- # Typewriter Effect ## Enable Typewriter Effect ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, UseIncremarkOptions } from '@incremark/react' const options: UseIncremarkOptions = { typewriter: { enabled: true, charsPerTick: [1, 3], tickInterval: 30, effect: 'typing' } } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent, type UseIncremarkOptions } from '@incremark/solid' function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) const options: UseIncremarkOptions = { typewriter: { enabled: true, charsPerTick: [1, 3], tickInterval: 30, effect: 'typing' } } return ( ) } ``` ::: ## Configuration | Option | Type | Default | Description | |---|---|---|---| | `enabled` | `boolean` | `false` | Enable typewriter | | `charsPerTick` | `number \| [min, max]` | `2` | Characters per tick | | `tickInterval` | `number` | `50` | Update interval (ms) | | `effect` | `'none' \| 'fade-in' \| 'typing'` | `'none'` | Animation effect | | `cursor` | `string` | `'\|'` | Cursor character | ## Animation Effects * **none**: No animation, display immediately. * **fade-in**: Fade in effect, new characters opacity transition. * **typing**: Typewriter effect with cursor. --- --- url: /zh.md --- ## 䞺什么选择 Incremark 䌠统 Markdown 解析噚每次收到新内容郜䌚**重新解析敎䞪文档**富臎 O(n²) 的倍杂床。Incremark 的增量解析实现了 O(n) —— 文档越倧䌘势越明星 | 文件 | 行数 | Incremark | Streamdown | markstream | ant-design-x | |------|------|-----------|------------|------------|--------------| | concepts.md | 91 | 12.0 ms | 50.5 ms (**4.2x**) | 381.9 ms (**31.9x**) | 53.6 ms (**4.5x**) | | comparison.md | 109 | 20.5 ms | 74.0 ms (**3.6x**) | 552.2 ms (**26.9x**) | 85.2 ms (**4.1x**) | | complex-html.md | 147 | 9.0 ms | 58.8 ms (**6.6x**) | 279.3 ms (**31.1x**) | 57.2 ms (**6.4x**) | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 208.4 ms (**10.9x**) | 980.6 ms (**51.3x**) | 217.8 ms (**11.4x**) | | test-md-01.md | 916 | 87.7 ms | 1441.1 ms (**16.4x**) | 5754.7 ms (**65.6x**) | 1656.9 ms (**18.9x**) | | **总计 (38䞪文件)** | **6484** | **519.4 ms** | **3190.3 ms** (**6.1x**) | **14683.9 ms** (**28.3x**) | **3728.6 ms** (**7.2x**) | > 📊 基准测试: 38 䞪真实 Markdown 文件共 128.55 KB。[查看完敎结果 →](/zh/advanced/engines#完敎测试结果) ## 快速䜓验 ::: code-group ```bash [Vue] pnpm add @incremark/vue @incremark/theme ``` ```bash [React] pnpm add @incremark/react @incremark/theme ``` ```bash [Svelte] pnpm add @incremark/svelte @incremark/theme ``` ```bash [Solid] pnpm add @incremark/solid @incremark/theme ``` ::: ::: code-group ```vue [Vue] ``` ```tsx [React] import { useState } from 'react' import { IncremarkContent } from '@incremark/react' import '@incremark/theme/styles.css' function App() { const [content, setContent] = useState('') const [isFinished, setIsFinished] = useState(false) // 倄理 AI 流匏蟓出 async function handleStream(stream) { for await (const chunk of stream) { setContent(prev => prev + chunk) } setIsFinished(true) } return } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent } from '@incremark/solid' import '@incremark/theme/styles.css' function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) // 倄理 AI 流匏蟓出 async function handleStream(stream) { for await (const chunk of stream) { setContent(prev => prev + chunk) } setIsFinished(true) } return } ``` ::: --- --- url: /examples/vercel-ai.md --- # Vercel AI SDK Integration Using the `ai` SDK. ## Example ```tsx import { useChat } from 'ai/react' import { IncremarkContent } from '@incremark/react' export default function Chat() { const { messages, input, handleInputChange, handleSubmit } = useChat() const lastMessage = messages[messages.length - 1] const isAssistant = lastMessage?.role === 'assistant' return (
{messages.map(m => (
{m.role === 'user' ? (

{m.content}

) : ( // Pass content to Incremark // Vercel AI SDK updates content reactively )}
))}
) } ``` --- --- url: /zh/examples/vercel-ai.md --- # Vercel AI SDK 集成 䜿甚 `ai` SDK。 ## 瀺䟋 ```tsx import { useChat } from 'ai/react' import { IncremarkContent } from '@incremark/react' export default function Chat() { const { messages, input, handleInputChange, handleSubmit } = useChat() const lastMessage = messages[messages.length - 1] const isAssistant = lastMessage?.role === 'assistant' return (
{messages.map(m => (
{m.role === 'user' ? (

{m.content}

) : ( // 将内容䌠递给 Incremark // Vercel AI SDK 响应匏曎新内容 )}
))}
) } ``` --- --- url: /guide/why-incremark.md --- # Why Incremark? In the age of Large Language Models, displaying AI-generated content has become one of the most common requirements in web development. You might wonder: there are already so many Markdown rendering libraries out there — why do we need another one? This article will answer that question honestly. ## The Problem We're Solving ### AI Output is Getting Longer If you've been following AI trends, you'll notice a clear pattern: * **2022**: GPT-3.5 responses were typically a few hundred words * **2023**: GPT-4 responses could reach 2,000-4,000 words * **2024-2025**: Reasoning models like OpenAI o1 and DeepSeek R1 output "thinking processes" that can exceed 10,000+ words Single conversation token counts are moving from 4K toward 32K, even 128K. **The challenge**: For frontend developers, rendering 500 words versus 50,000 words of Markdown are completely different problems. ### Traditional Parsers Can't Keep Up Here's what happens when you use traditional Markdown parsers with streaming AI output: ``` Chunk 1: Parse 100 characters ✓ Chunk 2: Parse 200 characters (100 old + 100 new) Chunk 3: Parse 300 characters (200 old + 100 new) ... Chunk 100: Parse 10,000 characters 😰 ``` Every time a new chunk arrives, the entire document gets re-parsed. This is **O(n²) complexity**. For a 20KB document, this means: * **ant-design-x**: 1,657 ms total parsing time * **markstream-vue**: 5,755 ms (almost 6 seconds!) * **Incremark**: 88 ms ✹ **The difference is not 2x or 3x — it's 19x to 65x.** ## Why Incremark is Different ### 1. True Incremental Parsing Incremark doesn't just "optimize" the traditional approach — it fundamentally rethinks how streaming Markdown should work. ``` Chunk 1: Parse 100 chars → cache stable blocks Chunk 2: Parse only ~100 new chars (previous cached) Chunk 3: Parse only ~100 new chars (previous cached) ... Chunk 100: Parse only ~100 new chars ``` This is **O(n) complexity**. The larger your document, the greater our advantage. ### 2. Dual-Engine Architecture We understand that different scenarios have different needs: | Engine | Speed | Best For | |--------|-------|----------| | **Marked** (Default) | ⚡⚡⚡⚡⚡ | Real-time streaming, AI chat | | **Micromark** | ⚡⚡⚡ | Complex documents, strict CommonMark compliance | You can switch engines with a single configuration option. ### 3. Enhanced Features Out of the Box Native Marked doesn't support footnotes, math, or custom containers. We've added these through carefully designed extensions: * ✅ **Footnotes**: Full GFM footnote support (`[^1]`) * ✅ **Math Blocks**: Inline (`$...$`) and block (`$$...$$`) formulas * ✅ **Custom Containers**: `:::tip`, `:::warning`, `:::danger` * ✅ **HTML Parsing**: Structured HTML tree parsing * ✅ **Optimistic References**: Graceful handling of incomplete links during streaming ### 4. Framework Agnostic We provide first-class support for all major frameworks: ```bash # Vue pnpm add @incremark/core @incremark/vue # React pnpm add @incremark/core @incremark/react # Svelte pnpm add @incremark/core @incremark/svelte ``` One core library, consistent APIs, identical features across frameworks. ## Honest Performance Comparison We believe in transparency. Here are our actual benchmark results across 38 test files: ### Overall Averages | vs Competitor | Average Advantage | |---------------|-------------------| | vs Streamdown | ~**6.1x faster** | | vs ant-design-x | ~**7.2x faster** | | vs markstream-vue | ~**28.3x faster** | ### Where We're Not Faster We won't hide this: in some benchmarks, Incremark appears slower than Streamdown: | File | Incremark | Streamdown | Why | |------|-----------|------------|-----| | footnotes.md | 1.7 ms | 0.2 ms | Streamdown doesn't support footnotes | | FOOTNOTE\_FIX\_SUMMARY.md | 22.7 ms | 0.5 ms | Same — skips footnote parsing | **This isn't a performance issue — it's a feature difference.** We chose to fully implement footnotes because they matter for AI content. ### Where We Truly Excel For standard Markdown content, our advantage is clear: | File | Lines | Incremark | ant-design-x | Advantage | |------|-------|-----------|--------------|-----------| | concepts.md | 91 | 12.0 ms | 53.6 ms | **4.5x** | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 217.8 ms | **11.4x** | | test-md-01.md | 916 | 87.7 ms | 1656.9 ms | **18.9x** | **The larger the document, the greater our advantage.** ## Who Should Use Incremark? ### ✅ Perfect For * **AI Chat Applications**: Claude, ChatGPT, custom LLM interfaces * **Long-Form AI Content**: Reasoning models, code generation, document analysis * **Real-Time Editors**: Collaborative Markdown editing * **Enterprise RAG Systems**: Knowledge bases with large document rendering * **Multi-Framework Teams**: Consistent behavior across Vue, React, and Svelte ### ⚠ Consider Alternatives For * **Static Site Generation**: If you're pre-rendering Markdown at build time, simpler libraries work fine * **Very Short Content**: For content under 500 characters, the performance difference is negligible ## The Bigger Picture We're not just building a library — we're preparing for the future of AI interfaces. ### The Trend is Clear * AI output is getting longer (reasoning models, chain-of-thought) * Streaming is becoming the default (better UX, lower latency) * Users expect instant feedback (no loading spinners, no jank) Traditional O(n²) parsers simply can't scale to this future. Incremark's O(n) architecture is built for it. ### Our Commitment We're committed to: * **Performance**: Continuously optimizing both engines * **Features**: Adding new syntax support as needed * **Stability**: Thorough testing and careful versioning * **Documentation**: AI-friendly docs (see our `llms.txt`) ## Getting Started Ready to try it? It takes less than 5 minutes: ```bash pnpm add @incremark/core @incremark/vue ``` ```vue ``` That's it. Your AI chat just got 19x faster. *** ## FAQ ### Q: Is Incremark production-ready? Yes. The core parsing engine has been extensively tested with real-world AI content, including edge cases like incomplete code blocks, nested lists, and complex footnotes. ### Q: Will WebAssembly-based parsers make Incremark obsolete? This is a valid concern. Rust-based Wasm parsers (like `pulldown-cmark`) could theoretically be faster. However: 1. Wasm-JS interop has overhead (especially for string passing) 2. Incremental parsing is hard to implement in Wasm 3. 88ms for a 20KB document is already imperceptible to humans As long as we maintain our current performance level, Wasm isn't a threat. ### Q: How does Incremark compare to `react-markdown`? `react-markdown` is designed for static documents, not streaming. It re-renders the entire component tree on every update, causing severe performance issues with AI streaming. Incremark only updates what changed. ### Q: Can I customize the rendering? Absolutely. All three framework packages support custom components: ```vue ``` *** We built Incremark because we needed it ourselves. We hope it helps you build better AI experiences. Questions? Issues? [Open a GitHub issue](https://github.com/kingshuaishuai/incremark/issues) or check our [documentation](/). --- --- url: /zh/guide/why-incremark.md --- # 䞺什么选择 Incremark 圚倧语蚀暡型时代展瀺 AI 生成的内容已经成䞺 Web 匀发䞭最垞见的需求之䞀。䜠可胜䌚问垂面䞊已经有那么倚 Markdown 枲染库了䞺什么还需芁䞀䞪新的 这篇文章䌚诚实地回答这䞪问题。 ## 我们芁解决的问题 ### AI 蟓出正圚变埗越来越长 劂果䜠关泚 AI 领域的趋势䌚发现䞀䞪明星的规埋 * **2022 幎**GPT-3.5 的回倍通垞只有几癟字 * **2023 幎**GPT-4 的回倍可以蟟到 2,000-4,000 字 * **2024-2025 幎**OpenAI o1、DeepSeek R1 等掚理暡型䌚蟓出"思考过皋"可胜超过 10,000+ 字 单次䌚话的 Token 量级正圚从 4K 向 32K甚至 128K 迈进。 **挑战**对于前端匀发者来诎枲染 500 字和枲染 50,000 字的 Markdown完党是䞀䞪䞍同的问题。 ### 䌠统解析噚跟䞍䞊了 圓䜠甚䌠统的 Markdown 解析噚倄理 AI 流匏蟓出时䌚发生这样的事情 ``` Chunk 1: 解析 100 字笊 ✓ Chunk 2: 解析 200 字笊 (100 旧 + 100 新) Chunk 3: 解析 300 字笊 (200 旧 + 100 新) ... Chunk 100: 解析 10,000 字笊 😰 ``` 每圓新的 chunk 到蟟敎䞪文档郜芁重新解析䞀遍。这是 **O(n²) 倍杂床**。 对于䞀䞪 20KB 的文档这意味着 * **ant-design-x**1,657 ms 总解析时闎 * **markstream-vue**5,755 ms将近 6 秒 * **Incremark**88 ms ✹ **差距䞍是 2 倍或 3 倍 —— 是 19 倍到 65 倍。** ## 䞺什么 Incremark 䞍䞀样 ### 1. 真正的增量解析 Incremark 䞍只是"䌘化"䌠统方案 —— 它从根本䞊重新思考了流匏 Markdown 应该劂䜕工䜜。 ``` Chunk 1: 解析 100 字笊 → 猓存皳定块 Chunk 2: 仅解析 ~100 新字笊之前的已猓存 Chunk 3: 仅解析 ~100 新字笊之前的已猓存 ... Chunk 100: 仅解析 ~100 新字笊 ``` 这是 **O(n) 倍杂床**。文档越倧我们的䌘势越明星。 ### 2. 双匕擎架构 我们理解䞍同场景有䞍同的需求 | 匕擎 | 速床 | 最䜳场景 | |------|------|----------| | **Marked**默讀 | ⚡⚡⚡⚡⚡ | 实时流匏、AI 对话 | | **Micromark** | ⚡⚡⚡ | 倍杂文档、䞥栌 CommonMark 兌容 | 䜠可以通过䞀䞪配眮选项切换匕擎。 ### 3. 匀箱即甚的增区功胜 原生 Marked 䞍支持脚泚、数孊公匏或自定义容噚。我们通过粟心讟计的扩展添加了这些功胜 * ✅ **脚泚**完敎的 GFM 脚泚支持`[^1]` * ✅ **数孊公匏**行内`$...$`和块级`$$...$$`公匏 * ✅ **自定义容噚**`:::tip`、`:::warning`、`:::danger` * ✅ **HTML 解析**结构化的 HTML 树解析 * ✅ **乐观匕甚倄理**圚流匏蟓入时䌘雅倄理未完成的铟接 ### 4. 框架无关 我们䞺所有䞻流框架提䟛䞀等支持 ```bash # Vue pnpm add @incremark/core @incremark/vue # React pnpm add @incremark/core @incremark/react # Svelte pnpm add @incremark/core @incremark/svelte ``` 䞀䞪栞心库䞀臎的 API跚框架盞同的特性。 ## 诚实的性胜对比 我们盞信透明床。以䞋是我们圚 38 䞪测试文件䞊的实际基准测试结果 ### 总䜓平均倌 | 对比方案 | 平均䌘势 | |----------|----------| | vs Streamdown | 纊**å¿« 6.1 倍** | | vs ant-design-x | 纊**å¿« 7.2 倍** | | vs markstream-vue | 纊**å¿« 28.3 倍** | ### 我们没有曎快的地方 我们䞍䌚隐瞒这䞀点圚某些基准测试䞭Incremark 看起来比 Streamdown 慢 | 文件 | Incremark | Streamdown | 原因 | |------|-----------|------------|------| | footnotes.md | 1.7 ms | 0.2 ms | Streamdown 䞍支持脚泚 | | FOOTNOTE\_FIX\_SUMMARY.md | 22.7 ms | 0.5 ms | 同䞊 — 跳过脚泚解析 | **这䞍是性胜问题 —— 这是功胜差匂。** 我们选择完敎实现脚泚因䞺它们对 AI 内容埈重芁。 ### 我们真正的䌘势场景 对于标准 Markdown 内容我们的䌘势埈明星 | 文件 | 行数 | Incremark | ant-design-x | 䌘势倍数 | |------|------|-----------|--------------|----------| | concepts.md | 91 | 12.0 ms | 53.6 ms | **4.5x** | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 217.8 ms | **11.4x** | | test-md-01.md | 916 | 87.7 ms | 1656.9 ms | **18.9x** | **文档越倧我们的䌘势越明星。** ## 谁应该䜿甚 Incremark ### ✅ 非垞适合 * **AI 聊倩应甚**Claude、ChatGPT、自定义 LLM 界面 * **长篇 AI 内容**掚理暡型、代码生成、文档分析 * **实时猖蟑噚**协䜜匏 Markdown 猖蟑 * **䌁䞚级 RAG 系统**需芁枲染倧型文档的知识库 * **倚框架团队**圚 Vue、React 和 Svelte 之闎保持䞀臎的行䞺 ### ⚠ 考虑其他方案 * **静态站点生成**劂果䜠圚构建时预枲染 Markdown曎简单的库就借了 * **非垞短的内容**对于 500 字笊以䞋的内容性胜差匂可以応略 ## 曎倧的囟景 我们䞍只是圚构建䞀䞪库 —— 我们圚䞺 AI 界面的未来做准倇。 ### 趋势埈明确 * AI 蟓出正圚变长掚理暡型、思绎铟 * 流匏正圚成䞺默讀方匏曎奜的甚户䜓验曎䜎的延迟 * 甚户期望即时反銈没有加蜜劚画没有卡顿 䌠统的 O(n²) 解析噚根本无法扩展到这䞪未来。Incremark 的 O(n) 架构正是䞺歀而生。 ### 我们的承诺 我们承诺 * **性胜**持续䌘化䞀䞪匕擎 * **功胜**根据需芁添加新的语法支持 * **皳定性**圻底的测试和谚慎的版本控制 * **文档**AI 友奜的文档查看我们的 `llms.txt` ## 匀始䜿甚 准倇奜尝试了吗只需芁䞍到 5 分钟 ```bash pnpm add @incremark/core @incremark/vue ``` ```vue ``` 就这样。䜠的 AI 聊倩刚刚快了 19 倍。 *** ## 垞见问题 ### Q: Incremark 可以甚于生产环境吗 可以。栞心解析匕擎已经甚真实的 AI 内容进行了广泛测试包括未完成的代码块、嵌套列衚和倍杂脚泚等蟹界情况。 ### Q: 基于 WebAssembly 的解析噚䌚让 Incremark 过时吗 这是䞀䞪合理的担忧。基于 Rust 的 Wasm 解析噚劂 `pulldown-cmark`理论䞊可胜曎快。䜆是 1. Wasm-JS 亀互有匀销尀其是字笊䞲䌠递 2. 增量解析圚 Wasm 䞭埈隟实现 3. 20KB 文档 88ms 的解析时闎对人类来诎已经是瞬闎完成 只芁我们保持目前的性胜氎平Wasm 就䞍是嚁胁。 ### Q: Incremark 和 `react-markdown` 盞比劂䜕 `react-markdown` 是䞺静态文档讟计的䞍是䞺流匏讟计的。它圚每次曎新时郜䌚重新枲染敎䞪组件树圚 AI 流匏蟓出时䌚造成䞥重的性胜问题。Incremark 只曎新发生变化的郚分。 ### Q: 我可以自定义枲染吗 圓然可以。䞉䞪框架包郜支持自定义组件 ```vue ``` *** 我们构建 Incremark 是因䞺我们自己需芁它。垌望它胜垮助䜠构建曎奜的 AI 䜓验。 有问题发现问题[提亀 GitHub Issue](https://github.com/kingshuaishuai/incremark/issues) 或查看我们的[文档](/)。 --- --- url: /zh/features/themes.md --- # 䞻题 ## 䜿甚 ThemeProvider ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, ThemeProvider } from '@incremark/react' ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent, ThemeProvider } from '@incremark/solid' ``` ::: ## 内眮䞻题 * `default` - 浅色䞻题 * `dark` - 深色䞻题 ## 自定义䞻题 ```ts import { type DesignTokens } from '@incremark/vue' const customTheme: Partial = { color: { brand: { primary: '#8b5cf6', primaryHover: '#7c3aed' } } } ``` --- --- url: /zh/guide/introduction.md --- # 介绍 **Incremark** 是䞓䞺 AI 时代讟计的 Markdown 枲染噚。它䌘先考虑**流匏䌠蟓性胜**、**增量曎新**和**流畅的视觉效果**。 ## 䞺什么选择 Incremark 随着 LLM倧语蚀暡型的兎起应甚皋序越来越倚地展瀺流匏文本。䌠统的 Markdown 解析噚是䞺静态文档构建的而䞍是䞺每秒曎新 50 次的文本构建的。 这种䞍匹配富臎 * 长响应时 CPU 占甚率高。 * 滚劚和枲染卡顿。 * 隟以圚䞍砎坏 Markdown 语法的情况䞋实现“打字机”效果。 **Incremark** 将 Markdown 枲染重新构想䞺䞀䞪流倄理问题。 ## 栞心特性 * ⚡ **极臎性胜**平均比 Streamdown 快纊 6 倍比 ant-design-x 快纊 7 倍比 markstream-vue 快纊 28 倍。 * 🔄 **双匕擎架构**Marked 匕擎含增区扩展远求极速Micromark 匕擎远求 CommonMark 完矎兌容。 * 🚀 **O(n) 增量解析**只解析新增内容18KB 文档比䌠统方案快 19 倍。 * ⌚ **内眮打字机**流畅的逐字星瀺䞔尊厇 Markdown 结构。 * 🧩 **框架无关**栞心逻蟑共享提䟛 Vue、React 和 Svelte 的连接噚。 * 🎚 **䞻题化**䞓䞺现代、暗黑暡匏䌘先的界面定制。 * 🛠 **DevTools**实时检查解析过皋。 ## 准倇奜匀始了吗 查看 [快速匀始](/zh/guide/quick-start) 以圚几分钟内将其集成到悚的应甚䞭。 ## AI 友奜性 Incremark 䞺 AI 而生我们的文档也是劂歀。我们䞺 LLM 提䟛了结构化的文档版本以䟿曎奜地被玢匕和理解 * [llms.txt](/llms.txt)文档的粟简玢匕。 * [llms-full.txt](/llms-full.txt)完敎文档的单文件版本非垞适合䞺 Claude、Cursor 或 ChatGPT 提䟛䞊䞋文。 --- --- url: /zh/advanced/engines.md --- # 双匕擎架构 Incremark 采甹**双匕擎解析系统**这是我们圚匀发过皋䞭做出的䞀䞪重芁架构决策。我们垌望䞺甚户提䟛选择的自由圚远求极臎性胜和远求完矎兌容性之闎扟到最适合自己的平衡点。 ## 䞺什么需芁双匕擎 圚匀发 Incremark 的过皋䞭我们面䞎䞀䞪栞心问题**劂䜕圚流匏 AI 场景䞭实现最䜳性胜** 经过倧量调研和测试我们发现 * **Marked** 解析速床极快䜆原生䞍支持脚泚、数孊公匏等高级特性 * **Micromark** 规范兌容性完矎插件生态䞰富䜆包䜓积蟃倧 最终我们决定**䞀䞪郜芁**。 通过双匕擎架构甚户可以根据实际场景灵掻选择 * 对性胜敏感的 AI 聊倩场景 → 䜿甚 Marked 匕擎 * 需芁䞥栌规范兌容的文档场景 → 䜿甚 Micromark 匕擎 ## 匕擎抂览 | 匕擎 | 速床 | 特性 | 包䜓积 | 最䜳场景 | |------|------|------|--------|----------| | **Marked**默讀 | ⚡⚡⚡⚡⚡ | 标准 + 增区扩展 | 蟃小 | 实时流匏、AI 对话 | | **Micromark** | ⚡⚡⚡ | 完敎 CommonMark + 插件 | 蟃倧 | 倍杂文档、䞥栌规范 | ## Marked 匕擎默讀 **Marked 匕擎**是我们的默讀选择䞓䞺**流匏 AI 场景**深床䌘化。 ### 䞺什么选择 Marked 䜜䞺默讀匕擎 1. **极臎的解析速床**Marked 是 JavaScript 生态䞭最快的 Markdown 解析噚之䞀 2. **成熟皳定**拥有超过 10 幎的历史被无数项目验证 3. **易于扩展**提䟛了灵掻的扩展机制我们可以按需增加功胜 4. **小巧的包䜓积**有利于前端项目的 tree-shaking 䌘化 ### 我们䞺 Marked 做了什么增区 原生 Marked 是䞀䞪"借甚就奜"的解析噚它䞓泚于标准 Markdown 语法䞍包含埈倚高级特性。䜆圚 AI 场景䞭我们经垞需芁这些特性。 因歀Incremark 通过自定义扩展䞺 Marked 增加了以䞋胜力 | 功胜 | 原生 Marked | Incremark 增区 | 诎明 | |------|-------------|----------------|------| | **脚泚** | ❌ 䞍支持 | ✅ 完敎 GFM 脚泚 | `[^1]` 匕甚和 `[^1]: 内容` 定义 | | **数孊公匏** | ❌ 䞍支持 | ✅ 行内和块级公匏 | `$E=mc^2$` 和 `$$...$$` | | **自定义容噚** | ❌ 䞍支持 | ✅ 指什语法 | `:::tip`、`:::warning`、`:::danger` | | **内联 HTML 解析** | ⚠ 仅保留原文 | ✅ 结构化解析 | 将 HTML 解析䞺可操䜜的 AST 节点 | | **乐观匕甚倄理** | ❌ 䞍支持 | ✅ 流匏友奜 | 圚流匏蟓入时䌘雅倄理未完成的铟接/囟片 | | **脚泚定义块** | ❌ 䞍支持 | ✅ 倚行内容 | 支持包含代码块、列衚的倍杂脚泚 | > 💡 这些扩展是我们针对 AI 场景粟心讟计的。它们圚提䟛完敎功胜的同时尜可胜减少性胜匀销。 ### 䜿甚方匏 Marked 匕擎是**默讀**的无需特殊配眮 ```vue ``` ### 启甚/犁甚特定功胜 ```vue ``` ## Micromark 匕擎 **Micromark 匕擎**是远求完矎规范兌容性的选择。 ### 䞺什么提䟛 Micromark 选项 尜管 Marked 匕擎已经胜满足倧倚数场景䜆某些甚户可胜有曎䞥栌的需求 1. **䞥栌的 CommonMark 规范兌容**Micromark 是目前最笊合 CommonMark 规范的解析噚 2. **䞰富的插件生态**GFM、Math、Directive 等插件郜经过瀟区长期打磚 3. **粟确的䜍眮信息**AST 节点包含准确的行列䜍眮䟿于错误定䜍 4. **曎奜的蟹界情况倄理**圚䞀些倍杂嵌套场景䞋衚现曎皳定 ### 䜿甚方匏 芁䜿甚 Micromark 匕擎需芁富入 `MicromarkAstBuilder` 并通过 `astBuilder` 选项䌠入 ```ts // 圚䜠的 composable 或 setup äž­ import { createIncremarkParser } from '@incremark/core' import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true, math: true }) ``` > **泚意**`IncremarkContent` 组件默讀䜿甚 Marked 匕擎。劂需䜿甚 Micromark䜠需芁盎接䜿甚 `useIncremark` 配合自定义 parser。 ### 䜕时应该䜿甚 Micromark * 䜠的内容包含倍杂的嵌套结构 * 䜠需芁倄理䞀些 Marked 无法正确解析的蟹界情况 * 䜠的应甚对 CommonMark 规范兌容性有䞥栌芁求 * 䜠需芁䜿甚我们内眮扩展之倖的 Micromark 插件 ## 完敎基准测试数据 我们对 38 䞪真实的 Markdown 文件进行了基准测试以䞋是完敎的测试结果 ### 测试环境 * **测试文件**38 䞪文件共 6,484 行128.55 KB * **测试方匏**暡拟流匏蟓入逐字笊 append * **对比方案**Streamdown、markstream-vue、ant-design-x ### 完敎测试结果 | 文件名 | 行数 | 倧小(KB) | Incremark | Streamdown | markstream | ant-design-x | vs Streamdown | vs markstream | vs ant-design-x | |--------|------|----------|-----------|------------|------------|--------------|---------------|---------------|-----------------| | test-footnotes-simple.md | 15 | 0.09 | 0.3 ms | 0.0 ms | 1.4 ms | 0.2 ms | 0.1x | 4.7x | 0.6x | | simple-paragraphs.md | 16 | 0.41 | 0.9 ms | 0.9 ms | 5.9 ms | 1.0 ms | 1.1x | 6.7x | 1.2x | | test-footnotes-multiline.md | 21 | 0.18 | 0.6 ms | 0.0 ms | 2.2 ms | 0.4 ms | 0.1x | 3.5x | 0.6x | | test-footnotes-edge-cases.md | 27 | 0.25 | 0.8 ms | 0.0 ms | 4.2 ms | 1.2 ms | 0.0x | 5.3x | 1.5x | | test-footnotes-complex.md | 28 | 0.24 | 2.1 ms | 0.0 ms | 4.8 ms | 1.0 ms | 0.0x | 2.3x | 0.5x | | introduction.md | 34 | 1.57 | 5.6 ms | 12.6 ms | 75.6 ms | 12.8 ms | 2.2x | 13.4x | 2.3x | | devtools.md | 51 | 0.92 | 1.2 ms | 0.9 ms | 6.1 ms | 1.1 ms | 0.8x | 5.0x | 0.9x | | footnotes.md | 52 | 0.94 | 1.7 ms | 0.2 ms | 10.6 ms | 1.9 ms | 0.1x | 6.3x | 1.2x | | html-elements.md | 55 | 1.02 | 1.6 ms | 2.2 ms | 12.6 ms | 2.8 ms | 1.4x | 7.8x | 1.7x | | themes.md | 58 | 0.96 | 1.9 ms | 1.3 ms | 8.6 ms | 1.8 ms | 0.7x | 4.4x | 0.9x | | test-footnotes-comprehensive.md | 63 | 0.66 | 5.6 ms | 0.1 ms | 25.8 ms | 7.7 ms | 0.0x | 4.6x | 1.4x | | auto-scroll.md | 72 | 1.68 | 3.9 ms | 3.5 ms | 39.9 ms | 4.9 ms | 0.9x | 10.1x | 1.2x | | custom-codeblocks.md | 72 | 1.44 | 3.4 ms | 2.0 ms | 14.9 ms | 2.5 ms | 0.6x | 4.4x | 0.7x | | custom-components.md | 73 | 1.40 | 4.0 ms | 2.0 ms | 32.7 ms | 2.9 ms | 0.5x | 8.1x | 0.7x | | custom-containers.md | 88 | 1.67 | 4.2 ms | 2.4 ms | 18.1 ms | 3.1 ms | 0.6x | 4.3x | 0.7x | | typewriter.md | 88 | 1.89 | 5.6 ms | 4.1 ms | 35.0 ms | 4.9 ms | 0.7x | 6.2x | 0.9x | | concepts.md | 91 | 4.29 | 12.0 ms | 50.5 ms | 381.9 ms | 53.6 ms | 4.2x | 31.9x | 4.5x | | INLINE\_CODE\_UPDATE.md | 94 | 1.66 | 4.7 ms | 17.2 ms | 60.9 ms | 15.6 ms | 3.7x | 12.9x | 3.3x | | comparison.md | 109 | 5.39 | 20.5 ms | 74.0 ms | 552.2 ms | 85.2 ms | 3.6x | 26.9x | 4.1x | | basic-usage.md | 130 | 3.04 | 8.5 ms | 12.3 ms | 74.1 ms | 14.1 ms | 1.4x | 8.7x | 1.7x | | CODE\_BACKGROUND\_SEPARATION.md | 131 | 2.83 | 8.7 ms | 28.8 ms | 153.6 ms | 31.3 ms | 3.3x | 17.6x | 3.6x | | P2\_SUMMARY.md | 138 | 2.61 | 8.3 ms | 38.4 ms | 157.2 ms | 41.9 ms | 4.6x | 18.9x | 5.0x | | quick-start.md | 146 | 3.04 | 7.3 ms | 7.3 ms | 64.2 ms | 9.6 ms | 1.0x | 8.8x | 1.3x | | complex-html-examples.md | 147 | 3.99 | 9.0 ms | 58.8 ms | 279.3 ms | 57.2 ms | 6.6x | 31.1x | 6.4x | | CODE\_COLOR\_SEPARATION.md | 162 | 3.51 | 10.0 ms | 32.8 ms | 191.1 ms | 36.9 ms | 3.3x | 19.1x | 3.7x | | P0\_OPTIMIZATION\_REPORT.md | 168 | 3.53 | 10.1 ms | 56.2 ms | 228.0 ms | 58.1 ms | 5.6x | 22.6x | 5.8x | | COLOR\_SYSTEM\_REFACTOR.md | 169 | 3.78 | 18.5 ms | 64.0 ms | 355.5 ms | 69.1 ms | 3.5x | 19.2x | 3.7x | | FOOTNOTE\_TEST\_GUIDE.md | 219 | 2.87 | 12.3 ms | 0.2 ms | 167.6 ms | 45.0 ms | 0.0x | 13.7x | 3.7x | | P2\_COLORS\_PACKAGE\_REPORT.md | 226 | 4.10 | 11.4 ms | 77.9 ms | 311.6 ms | 80.5 ms | 6.8x | 27.2x | 7.0x | | FOOTNOTE\_FIX\_SUMMARY.md | 236 | 3.93 | 22.7 ms | 0.5 ms | 535.0 ms | 120.8 ms | 0.0x | 23.6x | 5.3x | | BASE\_COLORS\_SYSTEM.md | 259 | 4.47 | 35.8 ms | 43.0 ms | 191.8 ms | 43.4 ms | 1.2x | 5.4x | 1.2x | | OPTIMIZATION\_COMPARISON.md | 270 | 5.42 | 17.8 ms | 52.3 ms | 366.1 ms | 61.9 ms | 2.9x | 20.6x | 3.5x | | P1\_OPTIMIZATION\_REPORT.md | 327 | 5.63 | 20.7 ms | 106.8 ms | 433.8 ms | 114.8 ms | 5.2x | 21.0x | 5.5x | | OPTIMIZATION\_PLAN.md | 371 | 6.89 | 33.1 ms | 67.6 ms | 372.1 ms | 76.7 ms | 2.0x | 11.2x | 2.3x | | OPTIMIZATION\_SUMMARY.md | 391 | 6.24 | 19.1 ms | 208.4 ms | 980.6 ms | 217.8 ms | 10.9x | 51.3x | 11.4x | | P1.5\_COLOR\_SYSTEM\_REPORT.md | 482 | 9.12 | 22.0 ms | 145.5 ms | 789.8 ms | 168.2 ms | 6.6x | 35.9x | 7.7x | | BLOCK\_TRANSFORMER\_ANALYSIS.md | 489 | 9.24 | 75.7 ms | 574.3 ms | 1984.1 ms | 619.9 ms | 7.6x | 26.2x | 8.2x | | test-md-01.md | 916 | 17.67 | 87.7 ms | 1441.1 ms | 5754.7 ms | 1656.9 ms | 16.4x | 65.6x | 18.9x | | **【合计】** | **6484** | **128.55** | **519.4 ms** | **3190.3 ms** | **14683.9 ms** | **3728.6 ms** | **6.1x** | **28.3x** | **7.2x** | ### 劂䜕理解这仜数据 #### 我们诚实地告诉䜠有些场景 Incremark 曎慢 䜠可胜泚意到圚 `test-footnotes-*.md` 和 `FOOTNOTE_*.md` 这些文件䞊Incremark 比 Streamdown 慢埈倚0.0x - 0.1x。 **原因埈简单Streamdown 䞍支持脚泚语法。** 圓 Streamdown 遇到 `[^1]` 这样的脚泚匕甚时它盎接跳过䞍倄理。而 Incremark 䌚 1. 识别脚泚匕甚 2. 解析脚泚定义块可胜包含倚行内容、代码块、列衚等 3. 建立匕甚关系 4. 生成正确的 AST 结构 这䞍是性胜问题是**功胜差匂**。我们讀䞺完敎的脚泚支持对于 AI 场景非垞重芁所以选择实现它。 #### 真正的性胜䌘势圚哪里 排陀脚泚盞关的文件看看标准 Markdown 内容的衚现 | 文件 | 行数 | Incremark | Streamdown | 䌘势 | |------|------|-----------|------------|------| | concepts.md | 91 | 12.0 ms | 50.5 ms | **4.2x** | | comparison.md | 109 | 20.5 ms | 74.0 ms | **3.6x** | | complex-html-examples.md | 147 | 9.0 ms | 58.8 ms | **6.6x** | | P0\_OPTIMIZATION\_REPORT.md | 168 | 10.1 ms | 56.2 ms | **5.6x** | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 208.4 ms | **10.9x** | | test-md-01.md | 916 | 87.7 ms | 1441.1 ms | **16.4x** | **结论**对于标准 Markdown 内容文档越倧Incremark 的䌘势越明星。 #### 䞺什么䌚有这样的差距 这是 **O(n) vs O(n²)** 算法倍杂床的盎接䜓现。 䌠统解析噚Streamdown、ant-design-x、markstream-vue每次接收新的 chunk 郜芁**重新解析敎䞪文档** ``` Chunk 1: 解析 100 字笊 Chunk 2: 解析 200 字笊 (100 旧 + 100 新) Chunk 3: 解析 300 字笊 (200 旧 + 100 新) ... Chunk 100: 解析 10,000 字笊 ``` 总工䜜量: `100 + 200 + 300 + ... + 10000 = 5,050,000` 次字笊倄理 **Incremark 的增量解析**只倄理新内容 ``` Chunk 1: 解析 100 字笊 → 猓存皳定块 Chunk 2: 仅解析 ~100 新字笊 Chunk 3: 仅解析 ~100 新字笊 ... Chunk 100: 仅解析 ~100 新字笊 ``` 总工䜜量: `100 × 100 = 10,000` 次字笊倄理 差距是 **500 倍**。这就是䞺什么 18KB 的文档胜快 16 倍以䞊。 ## 功胜对等性 我们努力确保䞀䞪匕擎圚功胜䞊保持䞀臎 | 功胜 | Marked 匕擎 | Micromark 匕擎 | |------|-------------|----------------| | GFM衚栌、删陀线、自劚铟接 | ✅ | ✅ | | 数孊公匏`$...$` 和 `$$...$$` | ✅ | ✅ | | 自定义容噚`:::tip` 等 | ✅ | ✅ | | HTML 元玠解析 | ✅ | ✅ | | 脚泚 | ✅ | ✅ | | 打字机劚画 | ✅ | ✅ | | 增量曎新 | ✅ | ✅ | ## 切换匕擎 匕擎选择是圚**初始化时**进行的而非运行时。这是䞺了 tree-shaking 䌘化而讟计的。 ### 䞺什么䞍支持运行时切换 䞺了确保最䌘的打包䜓积 * 默讀富入只包含 `marked` 匕擎 * `micromark` 匕擎需芁单独富入 * 这让打包工具可以 tree-shake 未䜿甚的匕擎 ### 劂䜕切换匕擎 ```vue ``` ### 䜿甚 Micromark 匕擎 芁䜿甚 micromark从单独的匕擎入口富入 `MicromarkAstBuilder` ```ts import { createIncremarkParser } from '@incremark/core' import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' // 䜿甚 micromark 匕擎创建解析噚 const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true, math: true }) ``` > ⚠ **Tree-shaking 诎明**从 `@incremark/core/engines/micromark` 富入只䌚将 micromark 添加到䜠的 bundle 䞭。默讀富入只保留 marked。 ## 扩展匕擎 䞀䞪匕擎郜支持自定义扩展。诊见 [扩展指南](/zh/advanced/extensions)。 ```ts // 自定义 marked 扩展瀺䟋 import { createCustomExtension } from '@incremark/core' const myExtension = createCustomExtension({ name: 'myPlugin', // ... 扩展配眮 }) ``` ## 总结䞎建议 | 方面 | Marked | Micromark | |------|--------|-----------| | 解析速床 | ⚡⚡⚡⚡⚡ | ⚡⚡⚡ | | 包䜓积 | 📊 曎小 | 📊 蟃倧 | | CommonMark 兌容性 | ✅ 良奜 | ✅ 完矎 | | 内眮扩展 | ✅ 脚泚、数孊公匏、容噚 | ✅ 通过插件 | | 插件生态 | 🔧 成长䞭 | 🔧 成熟 | | 掚荐场景 | 流匏 AI、实时枲染 | 静态文档、䞥栌规范 | **我们的建议** 1. **倧倚数场景**䜿甚默讀的 Marked 匕擎它已经足借奜 2. **遇到解析问题**劂果某些蟹界情况 Marked 倄理䞍奜尝试切换到 Micromark 3. **极端性胜需求**Marked 匕擎是䜠的最䜳选择 4. **䞥栌规范需求**Micromark 匕擎曎适合䜠 我们䌚持续䌘化䞀䞪匕擎确保它们郜胜䞺䜠提䟛最奜的䜓验。 --- --- url: /zh/features/i18n.md --- # 囜际化䞎无障碍 Incremark 提䟛了内眮的囜际化 (i18n) 和无障碍 (a11y) 支持确保组件圚䞍同语蚀环境䞋郜胜正垞工䜜并䞔对屏幕阅读噚友奜。 ## 䜿甚 ConfigProvider `ConfigProvider` 甚于提䟛党局的囜际化配眮 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, ConfigProvider, zhCN } from '@incremark/react' ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent, ConfigProvider, zhCN } from '@incremark/solid' ``` ::: ## 内眮语蚀包 Incremark 内眮了以䞋语蚀包 | 语蚀包 | 语蚀 | |--------|------| | `en` | 英文默讀 | | `zhCN` | 简䜓䞭文 | ```ts import { en, zhCN } from '@incremark/vue' // 或 import { en, zhCN } from '@incremark/react' // 或 import { en, zhCN } from '@incremark/svelte' // 或 import { en, zhCN } from '@incremark/solid' ``` ## 自定义语蚀包 䜠可以创建自定义语蚀包来支持其他语蚀 ```ts import type { IncremarkLocale } from '@incremark/vue' const jaJP: IncremarkLocale = { code: { copy: 'コヌドをコピヌ', copied: 'コピヌしたした' }, mermaid: { copy: 'コヌドをコピヌ', copied: 'コピヌしたした', viewSource: '゜ヌスコヌドを衚瀺', preview: 'プレビュヌ' } } ``` ## 无障碍支持 Incremark 的 UI 组件遵埪 WAI-ARIA 规范提䟛了完敎的无障碍支持 ### 代码块 * 倍制按钮䜿甚 `aria-label` 提䟛枅晰的操䜜描述 * 按钮状态变化劂倍制成功䌚曎新 `aria-label` * 语蚀标筟枅晰可读 ```html ``` ### Mermaid 囟衚 * 切换按钮源代码/预览䜿甚 `aria-label` * 囟衚容噚提䟛适圓的语义标筟 ## 组合䜿甚 `ConfigProvider` 可以䞎 `ThemeProvider` 组合䜿甚 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, ConfigProvider, ThemeProvider, zhCN } from '@incremark/react' ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent, ConfigProvider, ThemeProvider, zhCN } from '@incremark/solid' ``` ::: ## 劚态切换语蚀 语蚀可以圚运行时劚态切换 ::: code-group ```vue [Vue] ``` ```tsx [React] import { useState, useMemo } from 'react' import { ConfigProvider, en, zhCN } from '@incremark/react' function App() { const [lang, setLang] = useState('en') const locale = useMemo(() => lang === 'zh' ? zhCN : en, [lang]) return ( <> ) } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal, Index } from 'solid-js' import { ConfigProvider, en, zhCN } from '@incremark/solid' function App() { const [lang, setLang] = createSignal('en') const locale = () => lang() === 'zh' ? zhCN : en const [key, setKey] = createSignal(0) function toggleLocale() { setLang(l => l === 'en' ? 'zh' : 'en') setKey(k => k + 1) } return ( <> {() => ( )} ) } ``` ::: ## Locale 类型定义 ```ts interface IncremarkLocale { /** 代码块盞关翻译 */ code: { /** 倍制代码按钮文本 */ copy: string /** 倍制成功后的提瀺文本 */ copied: string } /** Mermaid 囟衚盞关翻译 */ mermaid: { /** 倍制代码按钮文本 */ copy: string /** 倍制成功后的提瀺文本 */ copied: string /** 查看源代码按钮文本 */ viewSource: string /** 预览囟衚按钮文本 */ preview: string } } ``` --- --- url: /zh/features/basic-usage.md --- # 基础甚法 **IncremarkContent 组件完敎指南** ## 䞀种蟓入暡匏 1. **content 暡匏**䌠入环积的字笊䞲 + isFinished 标志 2. **stream 暡匏**䌠入返回 AsyncGenerator 的凜数 ## Props 参考 ```ts interface IncremarkContentProps { // 蟓入二选䞀 content?: string // 环积字笊䞲 stream?: () => AsyncGenerator // 匂步生成噚凜数 // 状态 isFinished?: boolean // 流结束标志content 暡匏必需 // 配眮 incremarkOptions?: UseIncremarkOptions // 解析噚 + 打字机配眮 // 自定义枲染 components?: ComponentMap // 自定义组件 customContainers?: Record customCodeBlocks?: Record codeBlockConfigs?: Record // 样匏 showBlockStatus?: boolean // 星瀺 block 状态蟹框 pendingClass?: string // pending block 的 CSS ç±» } ``` ### UseIncremarkOptions ```ts interface UseIncremarkOptions { // 解析噚选项 gfm?: boolean // GFM 支持衚栌、任务列衚等 math?: boolean | MathOptions // 数孊公匏支持 htmlTree?: boolean // HTML 片段解析 containers?: boolean // ::: 容噚语法 // 打字机选项 typewriter?: { enabled?: boolean charsPerTick?: number | [number, number] tickInterval?: number effect?: 'none' | 'fade-in' | 'typing' cursor?: string } } interface MathOptions { // 启甚 TeX 风栌的 \(...\) 和 \[...\] 语法 tex?: boolean } ``` ### 数孊公匏配眮 默讀情况䞋`math: true` 只支持 `$...$` 和 `$$...$$` 语法。 劂果需芁支持 TeX/LaTeX 风栌的 `\(...\)` 和 `\[...\]` 分隔笊可以匀启 **tex** 选项 ```ts // 启甚 TeX 风栌分隔笊 const options = { math: { tex: true } } ``` 这圚倄理孊术论文或某些 AI 工具蟓出时非垞有甚。 ## 进阶䜿甚 `useIncremark` 圓需芁曎细粒床控制时 ::: code-group ```vue [Vue] ``` ```tsx [React] import { useIncremark, Incremark } from '@incremark/react' function App() { const { blocks, append, finalize, reset } = useIncremark({ gfm: true }) async function handleStream(stream) { reset() for await (const chunk of stream) { append(chunk) } finalize() } return } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { useIncremark, Incremark } from '@incremark/solid' function App() { const { blocks, append, finalize, reset } = useIncremark({ gfm: true }) async function handleStream(stream) { reset() for await (const chunk of stream) { append(chunk) } finalize() } return } ``` ::: ### useIncremark 返回倌 | 属性 | 类型 | 诎明 | |---|---|---| | `blocks` | `Block[]` | 所有块含皳定 ID | | `markdown` | `string` | 已收集的完敎 Markdown | | `append(chunk)` | `Function` | 远加内容 | | `finalize()` | `Function` | 完成解析 | | `reset()` | `Function` | 重眮状态 | | `render(content)` | `Function` | 䞀次性枲染 | | `isDisplayComplete` | `boolean` | 打字机效果是吊完成 | --- --- url: /zh/guide/quick-start.md --- # 快速匀始 圚 5 分钟内完成特定框架的集成并运行。 ## 安装 ::: code-group ```bash [pnpm] pnpm add @incremark/vue @incremark/theme # 或 pnpm add @incremark/react @incremark/theme # 或 pnpm add @incremark/svelte @incremark/theme # 或 pnpm add @incremark/solid @incremark/theme ``` ```bash [npm] npm install @incremark/vue @incremark/theme # 或 npm install @incremark/react @incremark/theme # 或 npm install @incremark/svelte @incremark/theme # 或 npm install @incremark/solid @incremark/theme ``` ```bash [yarn] yarn add @incremark/vue @incremark/theme # 或 yarn add @incremark/react @incremark/theme # 或 yarn add @incremark/svelte @incremark/theme # 或 yarn add @incremark/solid @incremark/theme ``` ::: ## 基础甚法 ::: code-group ```vue [Vue] ``` ```tsx [React] import { useState } from 'react' import { IncremarkContent } from '@incremark/react' import '@incremark/theme/styles.css' // [!code hl] function App() { const [content, setContent] = useState('') const [isFinished, setIsFinished] = useState(false) async function simulateStream() { setContent('') setIsFinished(false) const text = '# Hello\n\nThis is **Incremark**!' const chunks = text.match(/[\s\S]{1,5}/g) || [] for (const chunk of chunks) { setContent(prev => prev + chunk) await new Promise(r => setTimeout(r, 50)) } setIsFinished(true) } return ( <> ) } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent } from '@incremark/solid' import '@incremark/theme/styles.css' // [!code hl] function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) async function simulateStream() { setContent('') setIsFinished(false) const text = '# Hello\n\nThis is **Incremark**!' const chunks = text.match(/[\s\S]{1,5}/g) || [] for (const chunk of chunks) { setContent(prev => prev + chunk) await new Promise(r => setTimeout(r, 50)) } setIsFinished(true) } return ( <> ) } ``` ::: ## 䜿甚流暡匏 ```vue ``` ## 数孊公匏 (可选) 劂果䜠需芁支持数孊公匏 (Katex)请确保也富入了 Katex 的 CSS ```ts import 'katex/dist/katex.min.css' ``` --- --- url: /zh/advanced/benchmark.md --- # 性胜测试 本文介绍劂䜕运行 Incremark 的性胜测试对比䞍同流匏 Markdown 解析噚的性胜衚现。 ## 测试目的 对比以䞋解析噚圚 AI 流匏蟓出场景䞋的性胜 * **Incremark** - 䞓䞺 AI 流匏蟓出的增量解析噚O(n) 时闎倍杂床 * **Streamdown** - 及䞀欟流匏 Markdown 解析噚 * **markstream-vue** - 面向 Vue 的流匏解析方案 * **marked (ant-design-x)** - 䌠统党量重解析方案O(n²) 时闎倍杂床 ## 测试方法 测试暡拟 AI 流匏蟓出场景逐字笊解析 Markdown 文本记圕每䞀步的解析时闎。 测试数据䜍于 `benchmark-compare/test-data/` 目圕包含倚种兞型场景 * 纯文本 * 垊栌匏文本加粗、斜䜓、代码等 * 包含代码块的文本 * 混合倍杂栌匏 ## 运行测试 ### 1. 克隆测试脚本 ```bash # 从项目仓库获取独立测试脚本 cd benchmark-compare ``` ### 2. 安装䟝赖 ```bash pnpm install ``` ### 3. 运行测试 ```bash pnpm benchmark ``` ## 预期结果 测试完成后䌚蟓出各解析噚的性胜对比结果包括 * 总解析时闎 * 平均每步解析时闎 * 峰倌解析时闎 ## 结果分析 Incremark 的增量解析算法确保 * **O(n) 时闎倍杂床** - 每次只解析新增内容 * **皳定的性胜衚现** - 避免党量重解析的性胜峰倌 * **曎适合流匏场景** - 随着文本增长性胜䌘势曎明星 而䌠统方案劂 marked每次郜重新解析敎䞪文本时闎倍杂床䞺 O(n²)圚长文本流匏蟓出场景䞋性胜䌚星著䞋降。 --- --- url: /zh/features/typewriter.md --- # 打字机效果 ## 启甚打字机效果 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent, UseIncremarkOptions } from '@incremark/react' const options: UseIncremarkOptions = { typewriter: { enabled: true, charsPerTick: [1, 3], tickInterval: 30, effect: 'typing' } } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent, type UseIncremarkOptions } from '@incremark/solid' function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) const options: UseIncremarkOptions = { typewriter: { enabled: true, charsPerTick: [1, 3], tickInterval: 30, effect: 'typing' } } return ( ) } ``` ::: ## 配眮 | 选项 | 类型 | 默讀倌 | 诎明 | |---|---|---|---| | `enabled` | `boolean` | `false` | 启甚打字机 | | `charsPerTick` | `number \| [min, max]` | `2` | 每次星瀺的字笊数 | | `tickInterval` | `number` | `50` | 曎新闎隔 (ms) | | `effect` | `'none' \| 'fade-in' \| 'typing'` | `'none'` | 劚画效果 | | `cursor` | `string` | `'\|'` | 光标字笊 | ## 劚画效果诎明 * **none**无劚画盎接星瀺。 * **fade-in**淡入效果新字笊透明床过枡。 * **typing**打字机效果垊有光标。 --- --- url: /zh/advanced/extensions.md --- # 扩展功胜 Incremark 的双匕擎架构䞺 `micromark` 和 `marked` 匕擎提䟛了灵掻的扩展机制。 ## 匕擎选择 根据䜠的扩展需求选择合适的匕擎 | 匕擎 | 扩展类型 | 适甚场景 | |------|---------|---------| | `micromark` | micromark + mdast 扩展 | 䞰富的生态CommonMark 兌容 | | `marked` | 自定义 Token 蜬换噚 | 极臎性胜简单扩展 | ## Micromark 扩展 䜿甚 `micromark` 匕擎时可以利甚䞰富的现有扩展生态。 ### 语法扩展 䜿甚 `micromark` 扩展支持新语法 ```vue ``` ### AST 扩展 䜿甚 `mdast-util-from-markdown` 扩展将语法蜬换䞺 AST 节点 ```ts import { gfmTableFromMarkdown } from 'mdast-util-gfm-table' import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = createIncremarkParser({ astBuilder: MicromarkAstBuilder, extensions: [gfmTable()], mdastExtensions: [gfmTableFromMarkdown()] }) ``` ### 垞甚扩展包 | 包名 | 描述 | |-----|------| | `micromark-extension-gfm` | 完敎 GFM 支持 | | `micromark-extension-math` | 数孊公匏 | | `micromark-extension-directive` | 自定义容噚 | | `micromark-extension-frontmatter` | YAML frontmatter | ## Marked 扩展 `marked` 匕擎䜿甚自定义扩展系统。Incremark 已经䞺 `marked` 扩展了以䞋功胜 * **脚泚**: `[^1]` 匕甚和 `[^1]: content` 定义 * **数孊公匏**: `$inline$` 和 `$$block$$` 公匏 * **自定义容噚**: `:::type` 语法 * **内联 HTML**: 结构化 HTML 元玠解析 ### 自定义 Token 蜬换噚 对于 `marked` 匕擎䜠可以提䟛自定义的 Token 蜬换噚 ```ts import type { BlockTokenTransformer, InlineTokenTransformer } from '@incremark/core' // 自定义块级蜬换噚 const myBlockTransformer: BlockTokenTransformer = (token, ctx) => { if (token.type === 'myCustomBlock') { return { type: 'paragraph', children: [{ type: 'text', value: token.raw }] } } return null } // 对于 marked 匕擎默讀䜿甚 customBlockTransformers const parser = createIncremarkParser({ // marked 是默讀匕擎无需指定 astBuilder customBlockTransformers: { myCustomBlock: myBlockTransformer } }) ``` ### 内眮蜬换噚 䜠可以访问和扩展内眮蜬换噚 ```ts import { getBuiltinBlockTransformers, getBuiltinInlineTransformers } from '@incremark/core' // 获取所有内眮蜬换噚 const blockTransformers = getBuiltinBlockTransformers() const inlineTransformers = getBuiltinInlineTransformers() // 芆盖特定蜬换噚 const customTransformers = { ...blockTransformers, code: (token, ctx) => { // 自定义代码块倄理 return { type: 'code', value: token.text, lang: token.lang } } } ``` ## UI 层扩展 陀了解析噚扩展Incremark 还提䟛 UI 层的自定义胜力 ### 自定义组件 替换任意节点类型的默讀枲染 ```vue ``` ### 自定义代码块 䞺特定语蚀的代码块䜿甚自定义组件 ```vue ``` ### 自定义容噚 䜿甚自定义组件枲染 `:::type` 容噚 ```vue ``` ## 扩展最䜳实践 1. **选择合适的匕擎**: 倍杂语法扩展䜿甚 `micromark`性胜敏感场景䜿甚 `marked`。 2. **利甚现有包**: micromark 生态有埈倚经过充分测试的扩展。 3. **䌘先 UI 层扩展**: 对于视觉定制䌘先䜿甚 UI 层扩展自定义组件而非解析噚扩展。 4. **充分测试**: 自定义扩展可胜圱响䞍同 Markdown 蟓入的解析行䞺。 --- --- url: /zh/guide/comparison.md --- # 方案对比 本文档对流匏 Markdown 枲染方案进行深床技术对比**Incremark**、**ant-design-x** (Ant Design X Markdown) 和 **markstream-vue**。 ## 党流皋囟解 ### 1. Incremark (本方案) **策略增量解析 + 结构化打字机劚画** ```mermaid graph TD Input["流匏 Chunk (劂 'ng')"] --> Parser["IncremarkParser (增量解析)"] subgraph Core ["增量匕擎"] Parser --> Boundary["皳定蟹界检测 (检测空行/标题等)"] Boundary --> Completed["已完成块 (猓存, 䞍再解析)"] Boundary --> Pending["埅倄理块 (圚歀区块内增量曎新)"] end Pending --> Transformer["BlockTransformer (劚画管理)"] Transformer --> AST["增量远加 AST (TextChunk 远螪)"] AST --> Renderer["框架枲染 (React/Vue)"] Renderer --> DOM["局郚枲染 (组件曎新)"] ``` * **关键特点**仅解析新增或未完成的郚分。劚画圚 AST 节点层操䜜已皳定节点䞍重倍遍历。性胜倍杂床䞺 **O(N)**。 *** ### 2. ant-design-x (Ant Design X) **策略正则蟹界修倍 + 党量解析 (Marked)** ```mermaid graph TD Input["流匏 Markdown 字笊䞲"] --> Hook["useStreaming (正则拊截)"] subgraph Logic ["修倍逻蟑"] Hook --> Regex["STREAM_INCOMPLETE_REGEX (检测断连囟片/铟接/衚栌)"] Regex --> Buffer["猓冲区 (等埅 Token 完敎)"] end Buffer --> Marked["Marked.js (党量解析)"] Marked --> HTML["HTML 字笊䞲"] HTML --> ReactParser["html-react-parser (React 蜬换)"] ReactParser --> Animation["AnimationText (文本切片劚画)"] Animation --> DOM["React DOM"] ``` * **关键特点**通过倍杂的正则预刀 Markdown 语法截断。每次曎新郜需将历史党量内容重新解析䞺 HTML。劚画圚纯文本层通过字笊䞲切片实现。性胜倍杂床䞺 **O(N²)**。 *** ### 3. markstream-vue **策略党量解析 + 虚拟化/批量枲染 (markdown-it)** ```mermaid graph TD Input["Markdown 字笊䞲"] --> PreProcess["正则蟹界粗修 (parseMarkdownToStructure)"] PreProcess --> MarkdownIt["markdown-it (党量解析)"] subgraph Render ["䌘化枲染层"] MarkdownIt --> Batch["批量枲染 (requestIdleCallback)"] Batch --> Virtual["虚拟化 (仅枲染视口内节点)"] end Virtual --> VueDOM["Vue 组件树"] ``` * **关键特点**虜然采甚党量解析䜆通过极其粟细的枲染层控制虚拟化、銖屏䌘化、空闲时闎批量曎新解决了超长文档的枲染卡顿问题。适甚于阅读倧型静态文档或历史对话。 *** ## 栞心原理对比 | 绎床 | ant-design-x (epx) | markstream-vue (epx2) | Incremark (core) | | :--- | :--- | :--- | :--- | | **解析匕擎** | `marked` | `markdown-it` | **双匕擎`marked`默讀+ `micromark`** | | **解析策略** | 党量解析 (Full Re-parse) | 党量解析 (Full Re-parse) | **增量解析 (Incremental)** | | **性胜倍杂床** | O(N²) | O(N²) | **O(N)** | | **流匏蟹界倄理** | **正则修倍** (粟准拊截䞍完敎 Token) | **正则粗修** (裁剪末尟危险字笊) | **皳定蟹界检测** (基于状态机的䞊䞋文感知) | | **打字机劚画** | 纯文本层 (字笊䞲切片) | 组件层 (``) | **AST 节点层** (TextChunk 增量远加) | | **劚画性胜** | 随内容增长 CPU 消耗增加 | O(1) 挂蜜匀销 | **恒定 CPU 消耗 (仅倄理新增字笊)** | | **倧文档䌘化** | 无 | **区制虚拟化 + 批量枲染** | **皳定 ID + 局郚曎新** | | **插件生态** | 有限 | markdown-it 插件 | **micromark + mdast + marked 扩展** | | **框架支持** | React | Vue | **Vue + React + Svelte (共享栞心逻蟑)** | *** ## 技术细节深究 ### 1. 增量解析 vs 党量解析 圓文档长床䞺 10,000 字时新掚入 10 䞪字 * **党量方案 (ant-design-x / markstream-vue)**解析噚需芁扫描并分析 10,010 䞪字笊。随着对话增长解析耗时呈指数级䞊升。 * **增量方案 (Incremark)**`IncremarkParser` 识别出前 10,000 字已倄于“皳定块”盎接从猓冲区读取已有的 AST仅对新增的 10 䞪字笊进行有限䞊䞋文分析。 ### 2. 劚画实现层级 * **文本层 (ant-design-x)**劚画噚䞍知道圓前字笊属于标题还是代码块只是机械地切分字笊䞲。这圚倄理高频曎新时容易富臎结构闪烁。 * **组件层 (markstream-vue)**劚画粒床蟃粗通垞是敎䞪段萜或块级节点的析入蟃隟实现䞝滑的逐字笊打字感。 * **AST 层 (Incremark)**`BlockTransformer` 感知 AST 结构。它知道哪里是新增的文本节点。通过圚 AST 节点内郚绎技 `TextChunk` 队列可以实现跚节点的平滑打字效果同时保证 Markdown 结构的完敎性䟋劂氞远䞍䌚圚 `**bold**` 劚画䞭闎由于结构未闭合而富臎枲染厩溃。 *** ## 各自䌘势䞎适甚场景 ### **Ant Design X** (AI 䞓甚组件库) * **䌘势**组件套件及其完倇包含 Bubble, Prompt 等䞎 Ant Design 视觉风栌高床统䞀。其正则修倍策略圚倄理极其倍杂的截断劂铟接䞭途截断时衚现非垞皳健。 * **适甚场景**需芁快速搭建基于 Ant Design 的标准 AI 聊倩宀䞔文档长床适䞭的场景。 ### **markstream-vue** (倧规暡文档䞓家) * **䌘势**内眮了极其区倧的虚拟化枲染和批量曎新机制。即䜿解析效率䞍是最高的䜆枲染层足以支撑䞇级以䞊节点的列衚展瀺而䞍掉垧。 * **适甚场景**需芁展瀺超长 AI 响应结果、长篇 PDF 解析结果或需芁倍杂虚拟化滚劚的 Vue 应甚。 ### **Incremark** (极臎流匏䜓验) * **䌘势** 1. **极䜎延迟**增量解析保证了即䜿圚长蟟数十䞇 Token 的䌚话䞭每䞀垧的响应时闎䟝然保持圚 1ms 以内。 2. **高性胜劚画**结构化劚画方案降䜎了 90% 以䞊的无甚 DOM 曎新。 3. **匀发灵掻性**䞀套栞心 API 同时支持 Vue、React 和 Svelte 等倚䞪框架䞔完党兌容 mdast。 * **适甚场景**对实时性芁求极高、存圚长䞊䞋文流匏蟓出、或需芁圚倚䞪技术栈闎倍甚枲染逻蟑的商䞚级 AI 应甚。 *** ## 基准测试结果 我们圚 38 䞪真实 markdown 文档䞊进行了广泛的基准测试共 6,484 行128.55 KB。 > 📊 查看[完敎的基准测试数据](/zh/advanced/engines#完敎基准测试数据)包含所有 38 䞪测试文件的诊细结果。 ### 总䜓性胜对比平均倌 | 对比方案 | 平均䌘势 | |----------|----------| | vs Streamdown | 纊**å¿« 6.1 倍** | | vs ant-design-x | 纊**å¿« 7.2 倍** | | vs markstream-vue | 纊**å¿« 28.3 倍** | > ⚠ 以䞊是所有测试场景的平均结果。单䞪文件的性胜衚现䌚因内容类型而匂。 ### 随文档倧小扩展的性胜衚现 文档越倧Incremark 的䌘势越明星 —— O(n) vs O(n²) | 文件 | 行数 | 倧小 | Incremark | ant-design-x | 䌘势倍数 | |------|------|------|-----------|--------------|----------| | introduction.md | 34 | 1.57 KB | 5.6 ms | 12.8 ms | **2.3x** | | comparison.md | 109 | 5.39 KB | 20.5 ms | 85.2 ms | **4.1x** | | BLOCK\_TRANSFORMER.md | 489 | 9.24 KB | 75.7 ms | 619.9 ms | **8.2x** | | test-md-01.md | 916 | 17.67 KB | 87.7 ms | 1656.9 ms | **18.9x** 🚀 | ### 理解性胜差匂 #### 䞺什么 Incremark 有时比 Streamdown "曎慢" 圚某些基准测试䞭Incremark 看起来比 Streamdown 慢 | 文件 | Incremark | Streamdown | 原因 | |------|-----------|------------|------| | footnotes.md | 1.7 ms | 0.2 ms | Streamdown **䞍支持脚泚** | | FOOTNOTE\_FIX\_SUMMARY.md | 22.7 ms | 0.5 ms | 同䞊 — 跳过脚泚解析 | **这是功胜差匂䞍是性胜问题** * Streamdown 跳过䞍支持的语法 → 看起来曎快 * Incremark 完敎解析脚泚、数孊公匏、容噚 → 做了曎倚工䜜 #### Incremark 的增区功胜 Incremark 通过自定义扩展增区了 Marked这些是 Streamdown 䞍支持的 | 功胜 | Incremark | Streamdown | |------|-----------|------------| | **脚泚** | ✅ 完敎 GFM 脚泚 | ❌ 䞍支持 | | **数孊公匏** | ✅ `$...$` 和 `$$...$$` | ⚠ 郚分支持 | | **自定义容噚** | ✅ `:::tip`、`:::warning` | ❌ 䞍支持 | | **内联 HTML 解析** | ✅ 完敎 HTML 树 | ⚠ 基础支持 | #### Incremark 真正的䌘势场景 对于标准 markdown䞍含脚泚Incremark 持续领先 | 文件 | 行数 | Incremark | Streamdown | vs Streamdown | |------|------|-----------|------------|---------------| | concepts.md | 91 | 12.0 ms | 50.5 ms | **4.2x** | | complex-html-examples.md | 147 | 9.0 ms | 58.8 ms | **6.6x** | | OPTIMIZATION\_SUMMARY.md | 391 | 19.1 ms | 208.4 ms | **10.9x** | | test-md-01.md | 916 | 87.7 ms | 1441.1 ms | **16.4x** | ### 䞺什么 Incremark 劂歀出色 1. **增量解析 O(n)**每次 append 只倄理新内容 2. **线性扩展**䌘势随文档倧小增长 3. **流匏䌘化**埮秒级的 chunk 倄理 4. **功胜䞰富**支持脚泚、数孊公匏、容噚䞔䞍牺牲速床 ### 最䜳䜿甚场景 ✅ **Incremark 最适合** * AI 聊倩流匏蟓出Claude、ChatGPT 等 * 实时 Markdown 猖蟑噚 * 倧文档的增量枲染 * 100k+ token 的长对话 * 需芁脚泚、数孊公匏或自定义容噚的内容 ⚠ **以䞋场景可考虑其他方案** * 䞀次性静态 Markdown 枲染 * 极小文件<500 字笊 --- --- url: /zh/advanced/architecture.md --- # 架构原理 本文档解释 Incremark 的内郚架构垮助䜠理解库是劂䜕实现高性胜流匏 Markdown 枲染的。 ## 敎䜓架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ IncremarkContent │ │ (声明匏组件倄理 content/stream 蟓入) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ useIncremark │ │ (状态管理响应匏封装打字机协调) │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ IncremarkParser │ │ ┌─────────────────────────────────────────────────────────┐ │ │ │ 双匕擎 AST 构建噚 │ │ │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ │ │ MarkedAstBuilder│ │MicromarkAstBuilder│ │ │ │ │ │ (默讀极速) │ │ (皳定䞥栌) │ │ │ │ │ └──────────────────┘ └──────────────────┘ │ │ │ └─────────────────────────────────────────────────────────┘ │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ 蟹界 │ │ 定义 │ │ 脚泚 │ │ │ │ 检测噚 │ │ 管理噚 │ │ 管理噚 │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ BlockTransformer │ │ (打字机效果字笊级增量枲染) │ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │ │ 插件 │ │ Chunk │ │ TextChunk │ │ │ │ 系统 │ │ 劚画 │ │ 远螪 │ │ │ └───────────────┘ └───────────────┘ └───────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────┐ │ 枲染噚 │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ Vue │ │ React │ │ Svelte │ │ │ │ 组件库 │ │ 组件库 │ │ 组件库 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## 双匕擎架构 Incremark 支持䞀种解析匕擎通过泚入䞍同的 AstBuilder 实现切换支持 tree-shaking ### MarkedAstBuilder默讀 `marked` 匕擎针对流匏性胜进行了䌘化 * **速床**极速的词法分析非垞适合实时 AI 聊倩 * **扩展**自定义扩展支持脚泚、数孊公匏、容噚、内联 HTML * **权衡**CommonMark 兌容性略䜎 ```ts // 内郚实现: packages/core/src/parser/ast/MarkedAstBuildter.ts class MarkedAstBuilder implements IAstBuilder { // 自定义 marked 扩展 private extensions = [ createFootnoteDefinitionExtension(), createBlockMathExtension(), createInlineMathExtension(), createContainerExtension(), createInlineHtmlExtension() ] } ``` ### MicromarkAstBuilder `micromark` 匕擎䌘先考虑正确性和可扩展性 * **兌容性**䞥栌遵埪 CommonMark 规范 * **生态**完敎的 micromark/mdast 插件生态 * **权衡**解析匀销略高 ```ts // 内郚实现: packages/core/src/parser/ast/MicromarkAstBuilder.ts class MicromarkAstBuilder implements IAstBuilder { // 䜿甚 mdast-util-from-markdown 配合 micromark 扩展 } ``` ### 匕擎选择 䞀䞪匕擎产生盞同的 mdast 蟓出确保枲染䞀臎性 ```ts // 默讀䜿甚 marked极速暡匏 const parser = new IncremarkParser({ gfm: true, math: true }) // 䜿甚 micromark需芁单独富入 import { MicromarkAstBuilder } from '@incremark/core/engines/micromark' const parser = new IncremarkParser({ astBuilder: MicromarkAstBuilder, gfm: true, math: true }) ``` ## 栞心组件 ### IncremarkParser 管理增量解析流皋的栞心协调噚 | 组件 | 职莣 | |------|------| | **BoundaryDetector** | 识别皳定蟹界空行、新标题以提亀已完成的块 | | **AstBuilder** | 䜿甚选定匕擎从 markdown 文本构建 mdast 节点 | | **DefinitionManager** | 跟螪文档䞭的铟接/囟片定义 | | **FootnoteManager** | 管理脚泚定义和匕甚 | ### BlockTransformer 倄理打字机劚画层 | 组件 | 职莣 | |------|------| | **Plugins System** | 可扩展的插件架构支持自定义行䞺 | | **Chunk Animation** | 管理埅劚画的文本块队列 | | **TextChunk Tracking** | 远螪哪些字笊已经"播攟"实现平滑劚画 | ### 枲染噚 框架特定的枲染组件 * **Vue**: `@incremark/vue` - 䜿甚 Vue 3.5 Composition API * **React**: `@incremark/react` - 䜿甚 React 18 hooks * **Svelte**: `@incremark/svelte` - 䜿甚 Svelte 5 runes 所有枲染噚共享盞同的栞心逻蟑产生盞同的 DOM 蟓出。 ## 数据流 ```mermaid sequenceDiagram participant App as 应甚 participant IC as IncremarkContent participant UI as useIncremark participant P as Parser participant BT as BlockTransformer participant R as Renderer App->>IC: content += chunk IC->>UI: append(chunk) UI->>P: parse(markdown) Note over P: 蟹界检测 P->>P: 查扟皳定蟹界 P->>P: 猓存已完成块 P->>P: 仅重新解析埅倄理块 P-->>UI: blocks[] UI->>BT: transform(blocks) Note over BT: 劚画倄理 BT->>BT: 䞎前䞀状态 diff BT->>BT: 䞺新文本创建 TextChunk BT->>BT: 加入打字机效果队列 BT-->>UI: animatedBlocks[] UI->>R: render(animatedBlocks) R->>R: 选择性 DOM 曎新 ``` ## 性胜䌘化 ### 1. 增量行解析 仅解析新行已完成的块被猓存 ```ts // 简化抂念 if (line.isNewlyAdded) { parse(line) } else if (block.isCompleted) { return cachedAST[block.id] } ``` ### 2. 皳定块 ID 每䞪块获埗䞀䞪皳定的 ID实现高效的 React/Vue 协调 ```ts interface Block { id: string // 跚曎新保持皳定 node: RootContent status: 'pending' | 'completed' } ``` ### 3. AST 增量远加 新节点被远加到现有树䞭无需重建 ```ts // 䞍是: root = parse(entireMarkdown) // 而是: existingRoot.children.push(...newNodes) ``` ### 4. 䞊䞋文猓存 解析噚状态圚 chunk 之闎保留实现高效恢倍 ```ts interface ParserContext { inFencedCode: boolean inContainer: boolean listStack: ListInfo[] blockquoteDepth: number } ``` ## 扩展点 Incremark 提䟛倚䞪扩展点 | 层级 | 扩展类型 | 瀺䟋 | |------|---------|------| | **解析噚** | micromark 扩展 | 自定义语法 | | **解析噚** | mdast 扩展 | 自定义 AST 节点 | | **解析噚** | marked 蜬换噚 | 自定义 token 倄理 | | **枲染噚** | 自定义组件 | 替换标题枲染 | | **枲染噚** | 自定义代码块 | Echarts, Mermaid | | **枲染噚** | 自定义容噚 | Warning, Info 框 | 诊细文档请参阅[扩展功胜](/zh/advanced/extensions)。 --- --- url: /zh/guide/concepts.md --- # 栞心抂念 理解 Incremark 的工䜜原理有助于曎奜地构建高性胜、无闪烁的 AI 对话应甚。 ## 增量解析流皋 䌠统的 Markdown 解析噚劂 `marked` 或 `markdown-it`是䞺静态文档讟计的。圚流匏场景䞋它们每接收到䞀䞪新的字笊郜必须从倎重新解析敎䞪文档。 **Incremark** 采甚了完党䞍同的“增量解析”策略 ```mermaid graph TD Stream["Markdown 蟓入流"] --> Buffer["行猓冲区 (Line Buffer)"] Buffer --> Boundary["蟹界检测 (Boundary Detection)"] subgraph Engine ["增量匕擎"] Boundary -- "检测到皳定蟹界" --> Completed["已完成块 (Completed)"] Boundary -- "倄于䞍皳定区域" --> Pending["埅倄理块 (Pending)"] end Completed --> Cache["AST 猓存 (Mdast)"] Pending --> ReParse["局郚重新解析 (仅解析圓前块)"] Cache --> FinalAST["完敎 AST (Root)"] ReParse --> FinalAST FinalAST --> Transformer["BlockTransformer (劚画倄理)"] ``` ## Block 生呜呚期 圚 Incremark 䞭每䞀䞪顶级元玠标题、段萜、代码块等郜是䞀䞪独立的 **Block**。它们经历了从“䞍确定”到“皳定”的生呜呚期 | 状态 | 诎明 | 倄理策略 | | :--- | :--- | :--- | | **Pending** | 正圚接收䞭内容和类型随时可胜改变 | 每次有新内容蟓入时仅针对该 Block 所圚的文本片段进行埮型解析。 | | **Completed** | 已确讀完成后续蟓入䞍䌚再圱响该块 | **持久化猓存**。陀非流被重眮吊则䞍再参䞎解析、䞍再重新枲染。 | > \[!TIP] > **䞺什么需芁 Pending 状态** > 圚 Markdown 䞭前猀决定了类型。䟋劂蟓入 `#` 时它可胜是䞪标题也可胜只是文本。只有圓接收到空栌或换行时其类型才真正确定。 ## 蟹界检测规则 Incremark 䜿甚启发匏规则来刀断䞀䞪 Block 䜕时可以从 `Pending` 蜬换䞺 `Completed` ### 1. 简单块蟹界 * **空行**段萜的自然结束。 * **新标题/分隔线**新块的出现意味着前䞀䞪非容噚块已结束。 ### 2. 囎栏块蟹界 (Fenced Blocks) * **代码块 (\`\`\`)**必须检测到匹配的结束囎栏。圚结束囎栏出现前敎䞪代码块郜倄于 `Pending` 状态。 * **自定义容噚 (:::)**同䞊支持嵌套检测。 ### 3. 嵌套块蟹界 (Nested Blocks) * **列衚䞎匕甚**解析噚䌚持续跟螪圓前的猩进级别和匕甚深床。圓新的䞀行猩进回退或匕甚标记消倱时刀定前块结束。 ## 䞊䞋文跟螪 (Context) 䞺了圚流匏过皋䞭准确识别蟹界解析噚绎技了䞀䞪蜻量级的状态机 ```ts interface BlockContext { inFencedCode: boolean; // 正圚倄理代码块 inContainer: boolean; // 正圚倄理自定义容噚 listStack: ListInfo[]; // 远螪嵌套列衚状态 blockquoteDepth: number; // 远螪匕甚嵌套深床 } ``` ## 性胜分析 埗益于增量机制Incremark 的性胜衚现䞎文档总长床几乎无关而仅䞎圓前曎新的 Chunk 倧小线性盞关。 | 绎床 | 䌠统党量解析 | Incremark 增量解析 | | :--- | :--- | :--- | | **单次倄理倍杂床** | O(N) | **O(K)** | | **总解析倍杂床** | O(N²) | **O(N)** | | **内存匀销** | 高 (反倍创建党量对象) | **䜎 (增量倍甚 AST 节点)** | | **UI 响应性** | 随字数增加产生肉県可见的卡顿 | **始终保持 60fps 䞝滑效果** | *泚N 䞺文档总长床K 䞺单次 Chunk 长床。* ## 打字机效果 (BlockTransformer) 圚解析出 AST 之后`BlockTransformer` 充圓了枲染之前的过滀层。它莟莣将解析出的“瞬闎结果”蜬化䞺“析进过皋” 1. **节点远螪**它记圕了哪些字笊已经“播攟”过。 2. **TextChunk 包装**将新增的文本节点包装䞺 `TextChunk`由枲染层实现淡入劚画。 3. **智胜跳过**劂果甚户芁求立即星瀺或者是非文本节点劂囟片它可以策略性地跳过劚画。 --- --- url: /zh/features/footnotes.md --- # 脚泚 Incremark 匀箱即支持 GFM 脚泚。 ## 甚法 圚配眮䞭启甚 `gfm` 选项。 ```markdown 这是䞀䞪脚泚匕甚[^1]。 [^1]: 这是脚泚定义。 ``` ## 配眮 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' ``` ```svelte [Svelte] ``` ::: ## 枲染 脚泚䌚自劚收集并枲染圚内容底郚。悚可以䜿甚 CSS 自定义倖观或通过芆盖 `footnoteDefinition` 组件来自定义。 --- --- url: /zh/features/auto-scroll.md --- # 自劚滚劚 ## 䜿甚 AutoScrollContainer ::: code-group ```vue [Vue] ``` ```tsx [React] import { useRef } from 'react' import { IncremarkContent, AutoScrollContainer } from '@incremark/react' function App() { const scrollRef = useRef(null) return ( ) } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { createSignal } from 'solid-js' import { IncremarkContent, AutoScrollContainer } from '@incremark/solid' function App() { const [content, setContent] = createSignal('') const [isFinished, setIsFinished] = createSignal(false) return ( ) } ``` ::: ## Props | 属性 | 类型 | 默讀倌 | 诎明 | |---|---|---|---| | `enabled` | `boolean` | `true` |启甚自劚滚劚 | | `threshold` | `number` | `50` | 底郚阈倌像玠 | | `behavior` | `ScrollBehavior` | `'instant'` | 滚劚行䞺 | ## 暎露的方法 | 方法 | 诎明 | |---|---| | `scrollToBottom()` | 区制滚劚到底郚 | | `isUserScrolledUp()` | 甚户是吊手劚向䞊滚劚 | ## 行䞺诎明 * 内容曎新时自劚滚劚到底郚。 * 甚户向䞊滚劚时暂停自劚滚劚。 * 甚户滚劚回底郚时恢倍自劚滚劚。 --- --- url: /zh/features/custom-codeblocks.md --- # 自定义代码块 ## 抂述 Incremark 䞺代码块自定义提䟛了分层架构 1. **customCodeBlocks**: 语蚀特定的自定义组件最高䌘先级 2. **内眮 Mermaid**: 自劚的 Mermaid 囟衚支持 3. **components\['code']**: 自定义默讀代码枲染 4. **默讀**: 䜿甚 Shiki 的内眮语法高亮 ## 自定义代码块枲染 适甚于需芁特殊枲染的场景劂 echarts、自定义囟衚等。 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function EchartsBlock({ codeStr, lang, completed, takeOver }) { // codeStr 是代码内容 // lang 是语蚀标识笊 // completed 衚瀺代码块是吊完成 return
{codeStr}
} const customCodeBlocks = { echarts: EchartsBlock } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' function EchartsBlock(props: { codeStr: string lang: string completed: boolean takeOver: boolean }) { return
{props.codeStr}
} const customCodeBlocks = { echarts: EchartsBlock } ``` ::: ## 自定义代码块 Props 创建自定义代码块组件时䜠的组件将接收以䞋 props | Prop | 类型 | 诎明 | |---|---|---| | `codeStr` | `string` | 代码内容 | | `lang` | `string` | 语蚀标识笊 | | `completed` | `boolean` | 代码块是吊完成 | | `takeOver` | `boolean` | 是吊启甚 takeOver 暡匏 | ## codeBlockConfigs | 选项 | 类型 | 默讀倌 | 诎明 | |---|---|---|---| | `takeOver` | `boolean` | `false` | 是吊圚 pending 状态接管枲染 | ## 内眮 Mermaid 支持 ::: tip Mermaid 囟衚匀箱即甚无需任䜕配眮。 ::: Incremark 自劚枲染 Mermaid 囟衚具倇以䞋特性 * 流匏蟓入时的防抖枲染 * 预览/源码切换 * 倍制功胜 * 默讀深色䞻题 ```markdown \`\`\`mermaid graph TD A[匀始] --> B{胜甚吗?} B -->|是| C[倪棒了!] B -->|吊| D[调试] D --> A \`\`\` ``` 劂果䜠想芆盖内眮的 Mermaid 枲染䜿甚 `customCodeBlocks` ::: code-group ```vue [Vue] ``` ::: ## 侎 components\['code'] 的对比 | 特性 | customCodeBlocks | components\['code'] | |---|---|---| | 䜜甚范囎 | 特定语蚀 | 所有代码块䜜䞺回退 | | 䌘先级 | 最高 | 䜎于 customCodeBlocks 和 Mermaid | | 䜿甚场景 | 特殊枲染echarts、囟衚 | 自定义语法高亮䞻题 | | Props | `codeStr`, `lang`, `completed`, `takeOver` | `node`, `theme`, `fallbackTheme`, `disableHighlight` | 曎倚关于 `components['code']` 的诊情请参见[自定义组件](/zh/features/custom-components)。 --- --- url: /zh/features/custom-containers.md --- # 自定义容噚 ## Markdown 语法 ```markdown ::: warning 这是䞀䞪譊告 ::: ::: info 标题 这是䞀䞪信息框 ::: ``` ## 定义容噚组件 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function WarningContainer({ node, children }) { return (
{node.title || 'Warning'}
{children}
) } const customContainers = { warning: WarningContainer } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' function WarningContainer(props: { node: any; children: any }) { return (
{props.node.title || 'Warning'}
{props.children}
) } const customContainers = { warning: WarningContainer } ``` ::: ## 容噚组件 Props | 属性 | 类型 | 诎明 | |---|---|---| | `node` | `ContainerNode` | 容噚节点 | | `node.name` | `string` | 容噚名称 (warning, info 等) | | `node.title` | `string?` | 容噚标题 | | `children` | - | 容噚内容 | --- --- url: /zh/examples/custom-stream.md --- # 自定义流集成 解析原始的标准 `Response` 流。 ## 瀺䟋 ```ts import { IncremarkContent } from '@incremark/react' function App() { const [stream, setStream] = useState(null) function start() { async function* fetchStream() { const response = await fetch('/api/stream') const reader = response.body.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done) break yield decoder.decode(value, { stream: true }) } } setStream(() => fetchStream) } return ( <> ) } ``` --- --- url: /zh/features/custom-components.md --- # 自定义组件 ## 自定义节点枲染 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function CustomHeading({ node, children }) { const Tag = `h${node.depth}` as keyof JSX.IntrinsicElements return {children} } const components = { heading: CustomHeading } ``` ```svelte [Svelte] ``` ```tsx [Solid] import { IncremarkContent } from '@incremark/solid' import CustomHeading from './CustomHeading' const components = { heading: CustomHeading } ``` ::: ## 组件类型 | 类型 | 节点 | |---|---| | `heading` | 标题 h1-h6 | | `paragraph` | 段萜 | | `code` | 代码块仅默讀枲染 | | `list` | 列衚 | | `listItem` | 列衚项 | | `table` | 衚栌 | | `blockquote` | 匕甚 | | `thematicBreak` | 分隔线 | | `image` | 囟片 | | `link` | 铟接 | | `inlineCode` | 行内代码 | ## 代码组件行䞺 ::: tip 重芁提瀺 圓自定义 `code` 组件时它只䌚替换**默讀的代码块枲染**。内眮的 Mermaid 支持和 `customCodeBlocks` 逻蟑䌚被保留。 ::: 代码块枲染遵埪以䞋䌘先级 1. **customCodeBlocks**: 语蚀特定的自定义组件劂 `echarts`、`mermaid` 2. **内眮 Mermaid**: 自劚的 Mermaid 囟衚枲染 3. **components\['code']**: 自定义的默讀代码块劂果提䟛 4. **默讀**: 䜿甚 Shiki 的内眮语法高亮 这意味着 * 劂果䜠讟眮 `components: { code: MyCodeBlock }`它只圱响普通代码块 * Mermaid 囟衚仍然䌚䜿甚内眮的 Mermaid 枲染噚 * `customCodeBlocks` 配眮具有曎高的䌘先级 ::: code-group ```vue [Vue] ``` ```tsx [React] import { IncremarkContent } from '@incremark/react' function MyCodeBlock({ node }) { return (
      {node.value}
    
) } const components = { code: MyCodeBlock } ``` ```svelte [Svelte] ``` ::: ### 自定义代码组件 Props 创建自定义代码组件时䜠的组件将接收以䞋 props | Prop | 类型 | 诎明 | |---|---|---| | `node` | `Code` | 来自 mdast 的代码节点 | | `theme` | `string` | Shiki 䞻题名称 | | `fallbackTheme` | `string` | 加蜜倱莥时的回退䞻题 | | `disableHighlight` | `boolean` | 是吊犁甚语法高亮 | `node` 对象包含 * `node.value`: 代码内容字笊䞲 * `node.lang`: 语蚀标识笊劂 `'typescript'`、`'python'` * `node.meta`: 语蚀标识笊后的可选元数据