Skip to content

Markdown-it 插件扩展

VitePress 使用 Markdown-it 作为 Markdown 解析引擎。通过 Markdown-it 插件,你可以扩展 Markdown 语法,添加自定义解析规则和渲染行为。

Markdown-it 在 VitePress 中的位置

text
Markdown 源文件 (.md)

  Markdown-it 解析器

  HTML AST(抽象语法树)

  Vue 模板编译

  最终 HTML 输出

VitePress 通过 markdown.config 选项暴露 Markdown-it 实例,允许你注册插件:

typescript
// .vitepress/config.mts
import { defineConfig } from 'vitepress'

export default defineConfig({
  markdown: {
    config(md) {
      // 在此注册 Markdown-it 插件
      md.use(plugin1)
      md.use(plugin2, options)
    }
  }
})

安装与使用插件

基本用法

markdown-it-footnote(脚注插件)为例:

bash
npm install -D markdown-it-footnote
typescript
import footnote from 'markdown-it-footnote'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(footnote)
    }
  }
})

使用脚注语法:

markdown
这是一段包含脚注的文本[^1]。

[^1]: 这是脚注的内容。

带配置的插件

部分插件支持配置选项:

typescript
import anchor from 'markdown-it-anchor'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(anchor, {
        permalink: anchor.permalink.ariaHidden({
          placement: 'before',
          class: 'header-anchor'
        }),
        level: [2, 3]
      })
    }
  }
})

常用插件推荐

表格与格式

插件用途安装命令
markdown-it-footnote脚注支持npm i -D markdown-it-footnote
markdown-it-attrs为元素添加属性npm i -D markdown-it-attrs
markdown-it-mark标记高亮文本(==text==npm i -D markdown-it-mark
markdown-it-sub下标语法(H~2~Onpm i -D markdown-it-sub
markdown-it-sup上标语法(X^2^npm i -D markdown-it-sup
markdown-it-abbr缩写解释npm i -D markdown-it-abbr
markdown-it-deflist定义列表npm i -D markdown-it-deflist

数学公式

插件用途安装命令
markdown-it-katexKaTeX 数学公式npm i -D markdown-it-katex
markdown-it-mathjax3MathJax 3 数学公式npm i -D markdown-it-mathjax3

图表与嵌入

插件用途安装命令
markdown-it-mermaidMermaid 图表集成npm i -D markdown-it-mermaid
markdown-it-embed嵌入外部内容npm i -D markdown-it-embed

链接与导航

插件用途安装命令
markdown-it-anchor为标题添加锚点npm i -D markdown-it-anchor
markdown-it-toc-done-right目录生成npm i -D markdown-it-toc-done-right

典型插件配置示例

markdown-it-attrs

为 Markdown 元素添加 HTML 属性:

bash
npm install -D markdown-it-attrs
typescript
import attrs from 'markdown-it-attrs'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(attrs, {
        // 允许的属性
        allowedAttributes: ['id', 'class', 'style', 'target', 'rel']
      })
    }
  }
})

使用示例:

markdown
# 标题 {.custom-header #my-title}

![图片](url){width="300" .rounded}

[链接](url){target="_blank" rel="noopener"}

markdown-it-mark

高亮标记文本:

bash
npm install -D markdown-it-mark
typescript
import mark from 'markdown-it-mark'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(mark)
    }
  }
})

使用示例:

markdown
这是 ==高亮文本==,会渲染为 <mark>高亮文本</mark>。

markdown-it-abbr

缩写解释:

bash
npm install -D markdown-it-abbr
typescript
import abbr from 'markdown-it-abbr'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(abbr)
    }
  }
})

使用示例:

markdown
*[HTML]: Hyper Text Markup Language
*[W3C]:  World Wide Web Consortium

HTML 规范由 W3C 维护。

KaTeX 数学公式

bash
npm install -D markdown-it-katex
typescript
import katex from 'markdown-it-katex'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(katex)
    }
  },
  head: [
    ['link', {
      rel: 'stylesheet',
      href: 'https://cdn.jsdelivr.net/npm/katex@0.16/dist/katex.min.css'
    }]
  ]
})

行内公式和块级公式:

markdown
行内公式:$E = mc^2$

块级公式:

$$
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$

开发自定义插件

插件基本结构

一个 Markdown-it 插件是一个函数,接收 md 实例和可选配置:

typescript
// my-markdown-plugin.ts
import type MarkdownIt from 'markdown-it'
import type { RenderRule } from 'markdown-it/lib/renderer'

interface PluginOptions {
  className?: string
  tag?: string
}

export function myMarkdownPlugin(md: MarkdownIt, options: PluginOptions = {}) {
  const { className = 'custom', tag = 'div' } = options

  // 1. 添加解析规则(将文本解析为 token)
  md.inline.ruler.before('emphasis', 'my-syntax', (state, silent) => {
    // 解析逻辑
    // 返回 true 表示匹配成功
    return false
  })

  // 2. 添加渲染规则(将 token 渲染为 HTML)
  md.renderer.rules['my-syntax'] = (tokens, idx) => {
    const token = tokens[idx]
    return `<${tag} class="${className}">${token.content}</${tag}>`
  }
}

示例:自定义提示语法

开发一个 !!文字!! 语法,渲染为带样式的提示文本:

typescript
// markdown-it-highlight-tip.ts
import type MarkdownIt from 'markdown-it'

export function highlightTipPlugin(md: MarkdownIt) {
  // 解析规则:匹配 !!内容!!
  md.inline.ruler.before('emphasis', 'highlight-tip', (state, silent) => {
    const start = state.pos
    const max = state.posMax

    // 检查起始标记 !!
    if (state.src.charCodeAt(start) !== 0x21 /* ! */) return false
    if (state.src.charCodeAt(start + 1) !== 0x21 /* ! */) return false

    // 查找结束标记
    let pos = start + 2
    while (pos < max) {
      if (state.src.charCodeAt(pos) === 0x21 && state.src.charCodeAt(pos + 1) === 0x21) {
        // 找到结束标记
        if (!silent) {
          const token = state.push('highlight-tip', 'span', 1)
          token.markup = '!!'
          token.content = state.src.slice(start + 2, pos)

          const closingToken = state.push('highlight-tip', 'span', -1)
          closingToken.markup = '!!'
        }
        state.pos = pos + 2
        return true
      }
      pos++
    }

    return false
  })

  // 渲染规则
  md.renderer.rules['highlight-tip'] = (tokens, idx) => {
    const token = tokens[idx]
    if (token.nesting === 1) {
      // 开标签
      return `<span class="highlight-tip">`
    } else {
      // 闭标签
      return `</span>`
    }
  }
}

注册插件:

typescript
import { highlightTipPlugin } from './markdown-it-highlight-tip'

export default defineConfig({
  markdown: {
    config(md) {
      md.use(highlightTipPlugin)
    }
  }
})

添加样式:

css
/* .vitepress/theme/styles/highlight-tip.css */
.highlight-tip {
  background-color: var(--vp-c-brand-soft);
  padding: 2px 6px;
  border-radius: 4px;
  font-weight: 600;
}

示例:自定义容器插件

开发一个 !!! type 语法的高级容器:

typescript
// markdown-it-adv-container.ts
import type MarkdownIt from 'markdown-it'

interface ContainerOptions {
  types?: string[]
  render?: Record<string, (info: string) => { opening: string; closing: string }>
}

export function advancedContainerPlugin(md: MarkdownIt, options: ContainerOptions = {}) {
  const types = options.types || ['note', 'important', 'caution']

  // 为每种类型注册 block 规则
  for (const type of types) {
    const ruleName = `container_${type}`

    md.block.ruler.before('paragraph', ruleName, (state, startLine) => {
      const line = state.getLines(startLine, startLine + 1, 0, false).trim()

      // 匹配 !!! type 或 !!! type 标题
      const match = line.match(new RegExp(`^!!!\\s+${type}(?:\\s+(.+))?`))
      if (!match) return false

      // 查找结束标记 !!!
      let endLine = startLine + 1
      while (endLine < state.lineMax) {
        const endLineText = state.getLines(endLine, endLine + 1, 0, false).trim()
        if (endLineText === '!!!') break
        endLine++
      }

      // 创建 token
      const tokenOpen = state.push(`container_${type}_open`, 'div', 1)
      tokenOpen.markup = '!!!'
      tokenOpen.info = match[1] || type
      tokenOpen.attrSet('class', `adv-container adv-container--${type}`)

      // 解析内容
      const contentStart = startLine + 1
      const contentEnd = endLine
      state.md.block.parse(
        state.getLines(contentStart, contentEnd, 0, true),
        state.md,
        state.env,
        state.tokens
      )

      const tokenClose = state.push(`container_${type}_close`, 'div', -1)
      tokenClose.markup = '!!!'

      state.line = endLine + 1
      return true
    })
  }
}

插件开发调试

启用调试日志

typescript
export default defineConfig({
  markdown: {
    config(md) {
      // 打印解析过程中的 token
      md.core.ruler.push('debug-tokens', (state) => {
        console.log('Tokens:', state.tokens.map(t => ({
          type: t.type,
          tag: t.tag,
          content: t.content?.slice(0, 50)
        })))
        return true
      })
    }
  }
})

使用 Markdown-it Playground

在线测试 Markdown-it 插件:

  • Markdown-it Demo — 官方在线演示
  • 在浏览器控制台中实时调试解析过程

常见问题

问题原因解决方案
插件不生效插件注册顺序不对确保在 markdown.config 中正确注册
解析冲突多个插件匹配同一语法调整 ruler.before/after 顺序
SSR 报错插件包含浏览器 API使用条件导入或 onMounted
样式丢失CSS 未正确引入theme/index.ts 中引入样式文件

与 VitePress 内置功能的兼容性

避免冲突的内置语法

VitePress 已经内置了以下 Markdown-it 插件和功能,不需要重复安装

内置功能说明
表格GitHub 风格表格语法
Emoji:emoji: 短代码
目录[[toc]] 语法
自定义容器::: tip / ::: warning
代码组::: code-group
行高亮```ts{1,3-5}
数学公式$...$$$...$$
脚注[^note] 语法

避免冲突

不要安装与 VitePress 内置功能重复的插件(如 markdown-it-containermarkdown-it-emoji),否则可能导致解析冲突。

扩展内置容器

如果需要自定义容器类型,可以使用 VitePress 的 markdown.container 配置:

typescript
export default defineConfig({
  markdown: {
    container: {
      // 自定义容器标签
      tipLabel: '提示',
      warningLabel: '注意',
      dangerLabel: '警告',
      infoLabel: '信息'
    }
  }
})

最佳实践

  1. 最小化依赖 — 只安装必要的插件,避免与内置功能重复
  2. SSR 兼容 — 确保插件在 Node.js 环境中正常运行
  3. 性能优先 — 避免在解析规则中进行重量级计算
  4. 测试覆盖 — 为自定义插件编写单元测试
  5. 文档完善 — 记录插件支持的语法和配置选项
  6. 渐进增强 — 插件失败时不影响正常 Markdown 渲染

相关链接

贡献者

加载中...

想要成为贡献者?

在 CNB 上参与贡献