本文是《从零到一:构建现代化企业级 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 镜像构建
🔗 系列文章
- 📖 上一篇: 版本管理实战:Changeset 工作流完全指南
- 📖 下一篇: 《CI/CD 自动化:GitLab CI 完整流程》
- 🏠 专栏首页: 从零到一:构建现代化企业级 Monorepo 项目实战
文档站点搭建完成!觉得有帮助的话点个赞支持一下! 👍
你的文档站点用的什么工具?有什么优化技巧?评论区交流! 💬