VitePress 插件扩展记
CmdWise 文档站使用 VitePress 搭建,在 Markdown 中插入图标、流程图、图标等。本文记录了如何扩展 VitePress 插件,实现上述需求。
为什么要扩展?
- Mermaid 流程图
文档中已有多处 «```mermaid» 代码块,但默认 VitePress 不渲染,读者只能看到源码。需要图形化展示。 - 界面图标一致性
CmdWise App 已大量使用 Font Awesome 与 Lucide 图标。编写使用手册时,如果 Markdown 也能直接插入同款 SVG,可减少截图、保持 UI 与文档同步。
目标:在 不改动用户内容写法 的前提下,让
```mermaid、<font-awesome-icon>、<LucideIcon>等直接工作。
解决方案概览
| 需求 | 方案 | 关键包 |
|---|---|---|
| Mermaid 渲染 | 使用社区插件 vitepress-plugin-mermaid,一行包裹现有配置即可 | vitepress-plugin-mermaid, mermaid |
| Font Awesome 图标 | 全局注册 font-awesome-icon,并按需 library.add() 热门图标 | @fortawesome/vue-fontawesome + 三件套 |
| Lucide 图标 | 封装泛用组件 <LucideIcon>,内部动态查找 lucide-vue-next 组件 | lucide-vue-next |
核心代码
1. .vitepress/config.ts
ts
import { defineConfig } from 'vitepress'
import { withMermaid } from 'vitepress-plugin-mermaid'
export default withMermaid(defineConfig({
// 其余配置保持不变
}))2. package.json(docs 包)
jsonc
{
"devDependencies": {
"vitepress-plugin-mermaid": "^2.0.17",
"mermaid": "^10.9.1",
"@fortawesome/vue-fontawesome": "^3.0.3",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"lucide-vue-next": "^0.525.0",
"vue": "^3.4.21"
}
}3. 自定义主题 theme/index.ts
ts
import DefaultTheme from 'vitepress/theme'
import type { Theme } from 'vitepress'
import './custom.css'
// Font Awesome
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faTerminal, faBolt, faClipboard, faFile } from '@fortawesome/free-solid-svg-icons'
library.add(faTerminal, faBolt, faClipboard, faFile)
// Lucide
import * as LucideIcons from 'lucide-vue-next'
import { h, defineComponent } from 'vue'
const LucideIcon = defineComponent({
name: 'LucideIcon',
props: {
name: { type: String, required: true },
size: { type: [Number, String], default: 24 },
color: String,
strokeWidth: { type: [Number, String], default: 2 },
},
setup(props) {
const normalize = (n: string) => n.split(/[-_]/).map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('')
return () => {
const key = (LucideIcons as any)[props.name] ? props.name : normalize(props.name as string)
const Icon = (LucideIcons as any)[key]
return Icon ? h(Icon, { size: props.size, color: props.color, strokeWidth: props.strokeWidth }) : null
}
}
})
const theme: Theme = {
...DefaultTheme,
enhanceApp({ app }) {
(DefaultTheme as any).enhanceApp?.({ app })
app.component('FontAwesomeIcon', FontAwesomeIcon)
app.component('LucideIcon', LucideIcon)
},
}
export default theme遇到的问题 & 解决
| 问题 | 原因 | 解决办法 |
|---|---|---|
| 启动白屏 / Sidebar 丢失 | 一度尝试 批量注册 全部 Lucide 组件,与 VitePress 内置组件名冲突 | 放弃批量注册,改用 <LucideIcon> 动态加载,避免命名冲突 |
| 依赖解析失败 | 未同步安装 @fortawesome/vue-fontawesome、vue 等包 | 在 docs package.json 补充依赖,pnpm install 后恢复 |
| Mermaid 代码块仍显示源码 | 忘记用 withMermaid 包裹配置 | 在 config.ts 最外层用 withMermaid() 包裹 defineConfig() |
| 图标大小写不一致 | 开发者写 name="file",库实际为 File | normalize() 转换 kebab/snake → PascalCase 后再查找 |
结果
```mermaid代码块自动渲染为 SVG 图;- Markdown 可直接写
<font-awesome-icon icon="fa-solid fa-terminal" />; - Lucide 支持两种写法:md
<LucideIcon name="file" size="20" /> <lucide-icon name="camera" color="red" /> - 未引入的图标不会进最终 bundle,构建体积可控。