Skip to content

VitePress 插件扩展记

CmdWise 文档站使用 VitePress 搭建,在 Markdown 中插入图标、流程图、图标等。本文记录了如何扩展 VitePress 插件,实现上述需求。

为什么要扩展?

  1. Mermaid 流程图
    文档中已有多处 «```mermaid» 代码块,但默认 VitePress 不渲染,读者只能看到源码。需要图形化展示。
  2. 界面图标一致性
    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-fontawesomevue 等包在 docs package.json 补充依赖,pnpm install 后恢复
Mermaid 代码块仍显示源码忘记用 withMermaid 包裹配置config.ts 最外层用 withMermaid() 包裹 defineConfig()
图标大小写不一致开发者写 name="file",库实际为 Filenormalize() 转换 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,构建体积可控。