Skip to content

VitePress Plugin Extensions

CmdWise documentation site is built with VitePress, incorporating icons, flowcharts, and diagrams in Markdown. This article documents how to extend VitePress plugins to achieve these requirements.

Why Extend?

  1. Mermaid Flowcharts
    Documentation already contains multiple «```mermaid» code blocks, but default VitePress doesn't render them—readers only see source code. We need graphical display.

  2. Interface Icon Consistency
    CmdWise App already uses Font Awesome and Lucide icons extensively. When writing user manuals, if Markdown can directly insert the same SVG icons, it reduces screenshots and keeps UI and documentation synchronized.

Goal: Make ```mermaid, <font-awesome-icon>, <LucideIcon> work directly without changing user content syntax.

Solution Overview

RequirementSolutionKey Packages
Mermaid renderingUse community plugin vitepress-plugin-mermaid, wrap existing config with one linevitepress-plugin-mermaid, mermaid
Font Awesome iconsGlobally register font-awesome-icon, and library.add() popular icons on demand@fortawesome/vue-fontawesome + three packages
Lucide iconsWrap generic component <LucideIcon>, internally dynamic lookup lucide-vue-next componentslucide-vue-next

Core Code

1. .vitepress/config.ts

ts
import { defineConfig } from 'vitepress'
import { withMermaid } from 'vitepress-plugin-mermaid'

export default withMermaid(defineConfig({
  // Rest of configuration remains unchanged
}))

2. package.json (docs package)

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. Custom Theme 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

Issues Encountered & Solutions

ProblemCauseSolution
Startup white screen / Sidebar missingOnce tried batch registration of all Lucide components, conflicted with VitePress built-in component namesAbandoned batch registration, switched to <LucideIcon> dynamic loading to avoid naming conflicts
Dependency resolution failedFailed to sync install @fortawesome/vue-fontawesome, vue etc. packagesAdded dependencies to docs package.json, restored after pnpm install
Mermaid code blocks still show sourceForgot to wrap config with withMermaidWrap defineConfig() with withMermaid() in outermost layer of config.ts
Icon case inconsistencyDeveloper writes name="file", library actually has Filenormalize() converts kebab/snake → PascalCase then lookup

Results

  • ````mermaid` code blocks auto-render to SVG diagrams
  • Markdown can directly write <font-awesome-icon icon="fa-solid fa-terminal" />
  • Lucide supports two syntaxes:
    md
    <LucideIcon name="file" size="20" />
    <lucide-icon name="camera" color="red" />
  • Unused icons won't be included in final bundle, keeping build size controllable