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-footnotetypescript
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~O) | npm 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-katex | KaTeX 数学公式 | npm i -D markdown-it-katex |
markdown-it-mathjax3 | MathJax 3 数学公式 | npm i -D markdown-it-mathjax3 |
图表与嵌入
| 插件 | 用途 | 安装命令 |
|---|---|---|
markdown-it-mermaid | Mermaid 图表集成 | 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-attrstypescript
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}
{width="300" .rounded}
[链接](url){target="_blank" rel="noopener"}markdown-it-mark
高亮标记文本:
bash
npm install -D markdown-it-marktypescript
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-abbrtypescript
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-katextypescript
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-container、markdown-it-emoji),否则可能导致解析冲突。
扩展内置容器
如果需要自定义容器类型,可以使用 VitePress 的 markdown.container 配置:
typescript
export default defineConfig({
markdown: {
container: {
// 自定义容器标签
tipLabel: '提示',
warningLabel: '注意',
dangerLabel: '警告',
infoLabel: '信息'
}
}
})最佳实践
- 最小化依赖 — 只安装必要的插件,避免与内置功能重复
- SSR 兼容 — 确保插件在 Node.js 环境中正常运行
- 性能优先 — 避免在解析规则中进行重量级计算
- 测试覆盖 — 为自定义插件编写单元测试
- 文档完善 — 记录插件支持的语法和配置选项
- 渐进增强 — 插件失败时不影响正常 Markdown 渲染
相关链接
- Markdown-it 官方文档 — API 参考和插件开发指南
- Markdown-it 插件列表 — 社区插件
- Markdown 扩展语法 — VitePress 内置 Markdown 功能
- 插件开发指南 — VitePress 插件开发
- Vite 插件生态集成 — Vite 插件集成