VitePress 文档站点:打造专业级组件文档(含交互式示例)

本文是《从零到一:构建现代化企业级 Monorepo 项目实战》系列的第六篇。这篇文章将教你如何搭建一个媲美官方文档的专业文档站点。

🎯 本文目标

  • VitePress 在 Monorepo 中的集成
  • 组件示例自动导入和渲染
  • 自定义主题和样式
  • 文档站点性能优化
  • 部署配置

📖 为什么选择 VitePress?

文档工具对比

工具 性能 Vue 支持 Markdown 扩展 学习成本 推荐指数
VuePress ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
Docusaurus ⭐⭐⭐ ❌ React ⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
Docsify ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐
VitePress ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

VitePress 优势:

  • ⚡ 基于 Vite,开发和构建速度极快
  • 🎨 Vue 组件可以直接在 Markdown 中使用
  • 📝 Markdown 扩展能力强大
  • 🎯 专为 Vue 生态设计

🏗️ 项目结构设计

bash 复制代码
docs/
├── .vitepress/
│   ├── config.ts              # 配置文件
│   ├── theme/
│   │   ├── index.ts           # 主题入口
│   │   ├── components/
│   │   │   └── DemoBlock.vue  # 示例容器组件
│   │   └── custom.css         # 自定义样式
│   └── plugins/
│       └── demo-container.ts  # 自定义插件
├── components/
│   ├── button/
│   │   ├── index.md           # Button 文档
│   │   └── basic.vue          # 基础示例
│   └── index.md
├── guide/
│   ├── index.md
│   └── getting-started.md
├── index.md                   # 首页
└── package.json

🚀 第一步:安装和配置

1.1 安装 VitePress

bash 复制代码
cd docs
pnpm init
pnpm add -D vitepress vue

1.2 基础配置

typescript 复制代码
// docs/.vitepress/config.ts
import { defineConfig } from 'vitepress'
import { resolve } from 'path'

export default defineConfig({
  title: 'GDU Common',
  description: 'GDU 前端通用组件库和工具集',
  lang: 'zh-CN',

  // 主题配置
  themeConfig: {
    logo: '/logo.svg',

    nav: [
      { text: '指南', link: '/guide/' },
      { text: '组件', link: '/components/' },
      { text: '工具', link: '/utils/' },
    ],

    sidebar: {
      '/guide/': [
        {
          text: '开始',
          items: [
            { text: '介绍', link: '/guide/' },
            { text: '快速开始', link: '/guide/getting-started' },
          ],
        },
      ],
      '/components/': [
        {
          text: '组件',
          items: [{ text: 'Button 按钮', link: '/components/button' }],
        },
      ],
    },

    socialLinks: [{ icon: 'github', link: 'https://github.com/your-org/gdu-common' }],

    search: {
      provider: 'local', // 本地搜索
    },
  },

  // Vite 配置
  vite: {
    resolve: {
      alias: {
        '@gdu-common/ui': resolve(__dirname, '../../packages/ui/src'),
        '@gdu-common/utils': resolve(__dirname, '../../packages/utils/src'),
        '@gdu-common/shared': resolve(__dirname, '../../packages/shared/src'),
      },
    },
  },
})

1.3 添加脚本

json 复制代码
// docs/package.json
{
  "scripts": {
    "dev": "vitepress dev",
    "build": "vitepress build",
    "preview": "vitepress preview"
  }
}

🎨 第二步:自定义主题

2.1 创建自定义样式

css 复制代码
/* docs/.vitepress/theme/custom.css */

/* 首页渐变背景 */
:root {
  --vp-home-hero-name-color: transparent;
  --vp-home-hero-name-background: linear-gradient(120deg, #bd34fe 30%, #41d1ff);
}

/* 自定义品牌色 */
:root {
  --vp-c-brand-1: #42b983;
  --vp-c-brand-2: #35a069;
  --vp-c-brand-3: #299e5c;
}

/* 代码块样式优化 */
.vp-code-group {
  margin: 16px 0;
}

/* 表格样式 */
.vp-doc table {
  display: block;
  overflow-x: auto;
}

2.2 注册全局组件

typescript 复制代码
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
import './custom.css'

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    // 自动注册所有示例组件
    const examples = import.meta.glob('../../components/**/*.vue', {
      eager: true,
    })

    for (const path in examples) {
      const component = examples[path].default
      const name = path.match(/\/([^/]+)\.vue$/)?.[1]
      if (name) {
        app.component(name, component)
      }
    }
  },
}

🎭 第三步:交互式组件示例

3.1 创建 Demo 容器组件

vue 复制代码
<!-- docs/.vitepress/theme/components/DemoBlock.vue -->
<template>
  <div class="demo-block">
    <div class="demo-preview">
      <slot name="demo" />
    </div>

    <div class="demo-actions">
      <button @click="toggleCode" class="toggle-code-btn">
        {{ showCode ? '隐藏代码' : '查看代码' }}
      </button>
    </div>

    <div v-show="showCode" class="demo-code">
      <slot name="code" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const showCode = ref(false)
const toggleCode = () => {
  showCode.value = !showCode.value
}
</script>

<style scoped>
.demo-block {
  border: 1px solid var(--vp-c-divider);
  border-radius: 8px;
  margin: 16px 0;
}

.demo-preview {
  padding: 24px;
  background: var(--vp-c-bg-soft);
}

.demo-actions {
  padding: 12px 16px;
  border-top: 1px solid var(--vp-c-divider);
  display: flex;
  justify-content: flex-end;
}

.toggle-code-btn {
  padding: 4px 12px;
  font-size: 14px;
  border: 1px solid var(--vp-c-brand-1);
  color: var(--vp-c-brand-1);
  background: transparent;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s;
}

.toggle-code-btn:hover {
  background: var(--vp-c-brand-1);
  color: white;
}

.demo-code {
  border-top: 1px solid var(--vp-c-divider);
}
</style>

3.2 Markdown 自定义容器插件

typescript 复制代码
// docs/.vitepress/plugins/demo-container.ts
import MarkdownIt from 'markdown-it'
import container from 'markdown-it-container'
import { readFileSync } from 'fs'
import { resolve } from 'path'

export default (md: MarkdownIt) => {
  md.use(container, 'demo', {
    validate(params: string) {
      return params.trim().match(/^demo\s+(.*)$/)
    },

    render(tokens: any[], idx: number) {
      const token = tokens[idx]
      const info = token.info.trim().match(/^demo\s+(.*)$/)

      if (tokens[idx].nesting === 1) {
        // 开始标签
        const demoPath = info?.[1] || ''
        const filePath = resolve(__dirname, '../../components', `${demoPath}.vue`)
        const source = readFileSync(filePath, 'utf-8')

        return `
          <DemoBlock>
            <template #demo>
              <${demoPath.split('/').pop()} />
            </template>
            <template #code>
              
\`\`\`vue
${source}
\`\`\`

            </template>
          </DemoBlock>
          <div>
        `
      } else {
        // 结束标签
        return '</div>\n'
      }
    },
  })
}

3.3 在 config.ts 中注册插件

typescript 复制代码
import demoContainer from './plugins/demo-container'

export default defineConfig({
  markdown: {
    config: md => {
      md.use(demoContainer)
    },
  },
})

📝 第四步:编写组件文档

4.1 创建示例组件

vue 复制代码
<!-- docs/components/button/basic.vue -->
<template>
  <div class="demo">
    <Button>默认按钮</Button>
    <Button type="primary">主要按钮</Button>
    <Button type="success">成功按钮</Button>
  </div>
</template>

<script setup lang="ts">
import { Button } from '@gdu-common/ui'
</script>

<style scoped>
.demo {
  display: flex;
  gap: 12px;
}
</style>

4.2 编写文档

markdown 复制代码
<!-- docs/components/button.md -->

# Button 按钮

常用的操作按钮。

## 基础用法

最简单的按钮用法。

:::demo button/basic
:::

## API

### Props

| 属性     | 说明     | 类型                                  | 默认值      |
| -------- | -------- | ------------------------------------- | ----------- |
| type     | 按钮类型 | `'default' \| 'primary' \| 'success'` | `'default'` |
| size     | 按钮尺寸 | `'small' \| 'medium' \| 'large'`      | `'medium'`  |
| loading  | 加载状态 | `boolean`                             | `false`     |
| disabled | 禁用状态 | `boolean`                             | `false`     |

### Events

| 事件名 | 说明           | 回调参数                      |
| ------ | -------------- | ----------------------------- |
| click  | 点击按钮时触发 | `(event: MouseEvent) => void` |

### Slots

| 插槽名  | 说明       |
| ------- | ---------- |
| default | 按钮内容   |
| icon    | 自定义图标 |

效果:

  • 📖 文档和代码在一起,易于维护
  • 🎨 实时渲染的组件示例
  • 💻 可以查看源代码
  • 📱 响应式设计

🎨 第五步:首页定制

5.1 英雄区域

markdown 复制代码
## <!-- docs/index.md -->

layout: home

hero:
name: GDU Common
text: 企业级前端通用组件库
tagline: 基于 Vue 3 + TypeScript + Vite
image:
src: /logo.svg
alt: GDU Common
actions: - theme: brand
text: 快速开始
link: /guide/getting-started - theme: alt
text: 查看组件
link: /components/ - theme: alt  
 text: GitHub
link: https://github.com/your-org/gdu-common

---

5.2 特性展示

markdown 复制代码
features:

- icon: 🎨
  title: Vue 3 组件库
  details: 基于 Vue 3 Composition API 开发,提供丰富且高质量的 UI 组件
  link: /components/
  linkText: 查看组件
- icon: ⚡
  title: Vite & Turborepo
  details: 使用 Vite 极速构建,Turborepo 智能缓存,构建速度提升 19 倍
- icon: 🔧
  title: TypeScript 优先
  details: 完整的类型定义和智能提示,提供一流的开发体验
- icon: 📦
  title: Monorepo 架构
  details: 使用 pnpm workspace + Turborepo 管理,支持多包开发和发布

5.3 自定义样式

vue 复制代码
<!-- docs/index.md -->
<style>
:root {
  --vp-home-hero-name-color: transparent;
  --vp-home-hero-name-background: linear-gradient(-45deg, #bd34fe 30%, #41d1ff);

  --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe50 50%, #47caff50);
  --vp-home-hero-image-filter: blur(44px);
}

.VPFeature {
  transition: all 0.3s;
}

.VPFeature:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
}
</style>

📱 第六步:高级功能

6.1 组件 Playground

vue 复制代码
<!-- docs/.vitepress/theme/components/Playground.vue -->
<template>
  <div class="playground">
    <div class="playground-preview">
      <component :is="currentComponent" v-bind="props" />
    </div>

    <div class="playground-controls">
      <h4>属性配置</h4>
      <div v-for="(value, key) in props" :key="key" class="control-item">
        <label>{{ key }}</label>
        <input v-model="props[key]" />
      </div>
    </div>

    <div class="playground-code">
      <pre><code>{{ generatedCode }}</code></pre>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive } from 'vue'
import { Button } from '@gdu-common/ui'

const props = reactive({
  type: 'primary',
  size: 'medium',
  loading: false,
})

const currentComponent = Button

const generatedCode = computed(() => {
  const propsStr = Object.entries(props)
    .map(([key, val]) => `${key}="${val}"`)
    .join(' ')
  return `<Button ${propsStr}>点击我</Button>`
})
</script>

6.2 API 表格自动生成

typescript 复制代码
// docs/.vitepress/plugins/api-table.ts
import { readFileSync } from 'fs'
import { parse } from 'vue/compiler-sfc'

export function extractProps(filePath: string) {
  const source = readFileSync(filePath, 'utf-8')
  const { descriptor } = parse(source)

  // 解析 <script setup> 中的 defineProps
  const scriptContent = descriptor.script?.content || ''
  const propsMatch = scriptContent.match(/defineProps<(.+)>/)

  if (propsMatch) {
    // 提取 Props 类型定义
    return parsePropsType(propsMatch[1])
  }

  return []
}

6.3 暗黑模式支持

typescript 复制代码
// config.ts
export default defineConfig({
  appearance: true, // 启用暗黑模式切换

  themeConfig: {
    // 暗黑模式下的logo
    logo: {
      light: '/logo-light.svg',
      dark: '/logo-dark.svg',
    },
  },
})
css 复制代码
/* 暗黑模式样式 */
.dark .demo-block {
  border-color: var(--vp-c-divider);
  background: var(--vp-c-bg-soft);
}

🔧 第七步:Markdown 扩展

7.1 自定义容器

markdown 复制代码
::: tip 提示
这是一个提示信息
:::

::: warning 警告
这是一个警告信息
:::

::: danger 危险
这是一个危险警告
:::

::: details 点击查看详情
这是详细内容
:::

7.2 代码组

markdown 复制代码
::: code-group

\`\`\`bash [pnpm]
pnpm add @gdu-common/ui
\`\`\`

\`\`\`bash [npm]
npm install @gdu-common/ui
\`\`\`

\`\`\`bash [yarn]
yarn add @gdu-common/ui
\`\`\`

:::

7.3 代码高亮行

typescript 复制代码
// 高亮特定行
\`\`\`typescript {2,4-6}
function hello() {
  const name = 'world'  // [!code highlight]

  console.log('line 4')  // [!code highlight]
  console.log('line 5')  // [!code highlight]
  console.log('line 6')  // [!code highlight]
}
\`\`\`

// 标记添加/删除
\`\`\`typescript
function hello() {
  const name = 'world'   // [!code --]
  const name = 'Vue 3'   // [!code ++]
}
\`\`\`

📊 第八步:SEO 优化

8.1 Meta 标签配置

typescript 复制代码
export default defineConfig({
  head: [
    // SEO
    ['meta', { name: 'keywords', content: 'Vue3, 组件库, TypeScript, Monorepo' }],
    ['meta', { name: 'author', content: 'GDU Team' }],

    // Open Graph
    ['meta', { property: 'og:type', content: 'website' }],
    ['meta', { property: 'og:title', content: 'GDU Common' }],
    ['meta', { property: 'og:description', content: '企业级前端组件库' }],
    ['meta', { property: 'og:image', content: '/og-image.png' }],

    // Favicon
    ['link', { rel: 'icon', href: '/favicon.ico' }],
    ['link', { rel: 'apple-touch-icon', href: '/apple-touch-icon.png' }],
  ],

  // 最后更新时间
  lastUpdated: true,

  // 干净的 URL
  cleanUrls: true,
})

8.2 站点地图生成

typescript 复制代码
// docs/.vitepress/config.ts
export default defineConfig({
  sitemap: {
    hostname: 'https://gdu-common.example.com',
  },
})

🚀 第九步:性能优化

9.1 构建优化

typescript 复制代码
export default defineConfig({
  vite: {
    build: {
      // 代码压缩
      minify: 'terser',

      // 分包策略
      rollupOptions: {
        output: {
          manualChunks: {
            'vue-vendor': ['vue'],
            'vitepress-vendor': ['vitepress'],
          },
        },
      },

      // Chunk 大小警告
      chunkSizeWarningLimit: 1000,
    },
  },
})

9.2 图片优化

bash 复制代码
# 使用 webp 格式
docs/public/
├── logo.svg
├── hero.webp          # 首页图片
└── og-image.webp      # 社交分享图片

9.3 代码分割

typescript 复制代码
// 异步加载组件
export default {
  async enhanceApp({ app }) {
    if (!import.meta.env.SSR) {
      const HeavyComponent = await import('./components/HeavyComponent.vue')
      app.component('HeavyComponent', HeavyComponent.default)
    }
  },
}

📦 第十步:部署配置

10.1 静态站点部署

typescript 复制代码
export default defineConfig({
  base: '/', // 根目录部署
  // 或
  base: '/docs/', // 子目录部署

  outDir: '.vitepress/dist',
  cacheDir: '.vitepress/cache',
})

10.2 Nginx 配置

nginx 复制代码
server {
    listen 80;
    server_name docs.gdu-common.com;
    root /var/www/docs/.vitepress/dist;
    index index.html;

    # SPA 路由支持
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

10.3 Docker 部署

dockerfile 复制代码
# docs/Dockerfile
FROM node:20-alpine

WORKDIR /app

# 复制文件
COPY package.json pnpm-lock.yaml ./
COPY docs ./docs
COPY packages ./packages

# 安装依赖
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile

# 构建文档
RUN pnpm --filter @gdu-common/docs build

# 使用 nginx 服务
FROM nginx:alpine
COPY --from=0 /app/docs/.vitepress/dist /usr/share/nginx/html
COPY docs/nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

💡 最佳实践

1. 文档组织结构

bash 复制代码
docs/
├── guide/                 # 指南(给新手)
│   ├── index.md          # 介绍
│   ├── getting-started.md # 快速开始
│   └── installation.md   # 安装
├── components/            # 组件文档(给使用者)
│   ├── index.md
│   └── button.md
├── utils/                 # 工具文档
│   ├── index.md
│   └── common.md
└── advanced/              # 高级用法(给进阶用户)
    ├── customization.md
    └── theme.md

2. 示例代码规范

vue 复制代码
<!-- ✅ 好的示例 -->
<template>
  <!-- 清晰的HTML结构 -->
  <div class="demo">
    <Button @click="handleClick"> 点击次数:{{ count }} </Button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { Button } from '@gdu-common/ui'

// 简洁的逻辑
const count = ref(0)
const handleClick = () => {
  count.value++
}
</script>

<style scoped>
/* 必要的样式 */
.demo {
  padding: 20px;
}
</style>

3. 文档写作规范

markdown 复制代码
# ✅ 清晰的标题层级

# 组件名

## 基础用法

### 示例标题

#### 细节说明

# ✅ 代码示例在前,文字说明在后

:::demo button/basic
:::

按钮组件支持多种类型...

# ✅ 完整的 API 文档

## Props

## Events

## Slots

## Methods

📈 效果展示

构建性能

bash 复制代码
# 文档构建速度
pnpm --filter @gdu-common/docs build

vitepress v1.6.4
✓ building client + server bundles...
✓ rendering pages...

build complete in 4.3s

访问性能

指标 数值 说明
FCP 0.8s 首次内容绘制
LCP 1.2s 最大内容绘制
TTI 1.5s 可交互时间
总分 95/100 Lighthouse 性能分数

用户体验

  • ✅ 本地搜索(无需服务器)
  • ✅ 暗黑模式切换
  • ✅ 响应式设计
  • ✅ 代码一键复制
  • ✅ 交互式示例

🤔 常见问题

Q1: 如何在文档中引用组件?

typescript 复制代码
// 方式1:配置 alias
vite: {
  resolve: {
    alias: {
      '@gdu-common/ui': resolve(__dirname, '../../packages/ui/src')
    }
  }
}

// 方式2:直接导入
import { Button } from '@gdu-common/ui'

Q2: 如何实现组件的在线编辑?

typescript 复制代码
// 集成 @vue/repl
import { Repl } from '@vue/repl'

// 提供在线编辑环境
<Repl :store="store" />

Q3: 如何自动生成 API 文档?

bash 复制代码
# 使用 vue-docgen-api
pnpm add -D vue-docgen-api

# 解析组件生成 JSON
# 渲染成 Markdown 表格

Q4: 文档部署后 404 怎么办?

typescript 复制代码
// 配置正确的 base
export default defineConfig({
  base: '/', // 根目录
  // 或
  base: '/docs/', // 子目录

  cleanUrls: true, // 干净的 URL
})

🎁 完整示例

目录结构

arduino 复制代码
docs/
├── .vitepress/
│   ├── config.ts
│   ├── theme/
│   │   ├── index.ts
│   │   ├── components/
│   │   │   ├── DemoBlock.vue
│   │   │   └── Playground.vue
│   │   └── custom.css
│   └── plugins/
│       └── demo-container.ts
├── components/
│   ├── button/
│   │   ├── index.md
│   │   ├── basic.vue
│   │   ├── types.vue
│   │   └── loading.vue
│   └── index.md
├── guide/
│   ├── index.md
│   └── getting-started.md
├── public/
│   ├── logo.svg
│   └── favicon.ico
├── index.md
└── package.json

🎉 总结

VitePress 文档站点的核心价值:

技术实现

  • ✅ VitePress 配置和自定义主题
  • ✅ 交互式组件示例
  • ✅ 自动代码提取和高亮
  • ✅ SEO 和性能优化

实际效果

  • 📖 专业级文档体验
  • ⚡ 4.3s 构建,1.2s 加载
  • 🎨 美观的 UI 设计
  • 📱 完美的响应式

关键配置

bash 复制代码
pnpm doc:dev     # 开发
pnpm doc:build   # 构建
pnpm doc:preview # 预览

下一篇文章,我将分享 CI/CD 自动化流程,包括:

  • GitLab CI 配置
  • 自动化测试
  • 自动化发布
  • Docker 镜像构建

🔗 系列文章


文档站点搭建完成!觉得有帮助的话点个赞支持一下! 👍

你的文档站点用的什么工具?有什么优化技巧?评论区交流! 💬

相关推荐
崔庆才丨静觅4 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60615 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了5 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅5 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅6 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅6 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment6 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅6 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊6 小时前
jwt介绍
前端
yunteng5216 小时前
通用架构(同城双活)(单点接入)
架构·同城双活·单点接入