最近在写一个 VitePress 站点,想在文档中插入一些流程图和时序图,于是研究了一下如何在 VitePress 中集成 Mermaid。
为 VitePress 添加 Mermaid 图表支持:从原理到实现
在现代技术文档中,图表的重要性不言而喻。它们能够清晰地展示流程、架构和关系,让复杂的概念变得直观易懂。Mermaid 作为一个基于文本的图表绘制工具,以其简洁的语法和强大的功能受到了开发者的广泛喜爱。
本文将详细介绍如何为 VitePress 文档添加 Mermaid 图表支持,从核心思路到具体实现,帮助你在自己的项目中集成这一实用功能。
为什么需要特殊配置?
VitePress 默认使用 markdown-it 作为 Markdown 解析器,虽然它功能强大,但并不直接支持 Mermaid 图表的渲染。这是因为 Mermaid 图表的渲染需要在浏览器端执行 JavaScript,而传统的 Markdown 解析是在服务端完成的。
因此,我们需要一种机制,能够在服务端构建时识别 Mermaid 代码块,并将其转换为可在客户端渲染的 Vue 组件。
实现方案概述
我们的解决方案分为四个核心步骤:
- 创建
markdown-it插件识别 Mermaid 代码块 - 开发 Vue 组件负责客户端渲染
- 配置 VitePress 以集成插件和组件
- 解决构建过程中的模块加载问题
下面让我们详细看看每个步骤的具体实现。
定义 markdown-it 插件
我们首先创建了一个自定义的 markdown-it 插件 (mermaidPlugin.ts),可以在 plugins 文件夹下,用于拦截所有语言标记为 mermaid 的代码块:
// mermaidPlugin.ts
import type MarkdownIt from 'markdown-it';
export default function mermaidPlugin(md: MarkdownIt): void {
const fence = md.renderer.rules.fence?.bind(md.renderer.rules);
md.renderer.rules.fence = (tokens, idx, options, env, self) => {
const token = tokens[idx];
const language = token.info.trim();
if (language.startsWith('mermaid')) {
return `<Mermaid id="mermaid-${idx}" code="${encodeURIComponent(token.content)}"></Mermaid>`;
}
return fence!(tokens, idx, options, env, self);
};
}
这个插件的核心作用是拦截 Mermaid 代码块,将其替换为自定义的 Vue 组件标签,并将图表源代码作为属性传递给该组件。
定义 Mermaid Vue 组件
接下来,我们创建了 Mermaid.vue 组件,负责在客户端实际渲染图表:
<template>
<div class="mermaid-container" v-html="svgRef"></div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import mermaid from 'mermaid';
const props = defineProps<{
id: string;
code: string;
}>();
const svgRef = ref('');
const renderMermaid = async (id: string, code: string) => {
mermaid.initialize({ startOnLoad: false });
const { svg } = await mermaid.render(id, code);
return svg;
};
onMounted(async () => {
svgRef.value = await renderMermaid(props.id, decodeURIComponent(props.code));
});
</script>
这个组件接收编码后的 Mermaid 代码,在组件挂载后调用 Mermaid API 进行渲染,并通过 v-html 指令显示生成的 SVG。
第三步:配置 VitePress
安装依赖
首先安装必要的依赖:
pnpm add -D mermaid @types/markdown-it
注册全局组件
在主题配置文件 (index.ts) 中全局注册 Mermaid 组件:
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress';
import DefaultTheme from 'vitepress/theme';
import Mermaid from './components/Mermaid.vue';
export default {
extends: DefaultTheme,
enhanceApp: async ({ app }) => {
app.component('Mermaid', Mermaid);
},
} satisfies Theme;
配置 markdown-it 插件
在主配置文件 (config.mts) 中启用我们创建的插件:
// .vitepress/config.mts
import mermaidPlugin from './plugins/mermaidPlugin';
export default defineConfig({
markdown: {
config: (md) => {
md.use(mermaidPlugin);
},
},
});
第四步:解决构建问题
在配置过程中,我们遇到了一个常见的 ESM 模块加载错误。这是因为 VitePress 需要明确知道配置文件的模块格式。通过将配置文件从 config.ts 重命名为 config.mts,我们明确告知 VitePress 将其作为 ES 模块处理,从而解决了此问题。
使用示例
配置完成后,你可以在 Markdown 文件中直接使用 Mermaid 代码块:
```mermaid
graph TD
A[开始] --> B{判断}
B -->|是| C[执行操作]
B -->|否| D[结束]
C --> D
```
graph TD
A[开始] --> B{判断}
B -->|是| C[执行操作]
B -->|否| D[结束]
C --> D
VitePress 会自动将其渲染为对应的流程图。
总结
通过本文介绍的方法,我们成功为 VitePress 添加了 Mermaid 图表支持。这种方案的核心思路是:
- 在服务端构建时,通过
markdown-it插件识别 Mermaid 代码块 - 将其替换为自定义 Vue 组件并传递代码参数
- 在客户端由 Vue 组件调用 Mermaid 库完成实际渲染
这种架构既保持了服务端构建的效率,又利用了客户端渲染的灵活性,是一种优雅的解决方案。