VitePress 简介
什么是 VitePress?
VitePress 是 VuePress 的继任者,由 Vue.js 团队开发,基于 Vite 构建。它专为创建文档网站而设计,同时也适用于博客、产品介绍页面等内容驱动型网站。
VitePress 的主要特点:
- 极速开发体验:基于 Vite 的即时热更新(HMR)
- Vue 3 驱动:在 Markdown 中使用 Vue 组件
- 轻量级:生成的静态资源体积小
- 开箱即用:内置主题、搜索、导航等功能
- 高度可定制:支持自定义主题和布局
VitePress vs VuePress
| 特性 | VitePress | VuePress |
| 构建工具 | Vite | Webpack |
| Vue 版本 | Vue 3 | Vue 2/3 |
| 开发启动速度 | 毫秒级 | 秒级 |
| 热更新速度 | 即时 | 较慢 |
| 默认主题 | 现代化设计 | 经典设计 |
| 体积 | 更轻量 | 较重 |
谁在使用 VitePress?
许多知名项目都选择 VitePress 作为文档工具:
- Vue.js - Vue 3 官方文档
- Vite - Vite 官方文档
- Vitest - Vitest 测试框架文档
- Pinia - Vue 状态管理库文档
- Element Plus - Vue 3 UI 组件库文档
快速开始
环境要求
- Node.js 18 或更高版本
- npm/yarn/pnpm 包管理器
创建新项目
方法一:使用向导创建(推荐)
npx vitepress init
pnpm dlx vitepress init
yarn dlx vitepress init
向导会询问几个简单的问题:
┌ Welcome to VitePress!
│
◇ Where should VitePress initialize the config?
│ ./docs
│
◇ Site title:
│ My Awesome Docs
│
◇ Site description:
│ A VitePress Site
│
◇ Theme:
│ Default Theme + Customization
│
◇ Use TypeScript for config and theme files?
│ Yes
│
◇ Add VitePress npm scripts to package.json?
│ Yes
│
└ Done! Now run npm run docs:dev and start writing.
方法二:手动创建
mkdir my-docs && cd my-docs
npm init -y
npm install -D vitepress
mkdir docs && echo '# Hello VitePress' > docs/index.md
在 package.json 中添加脚本:
{
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
}
}
启动开发服务器
访问 http://localhost:5173 即可预览你的文档站点。
项目结构
标准目录结构
my-docs/
├── docs/
│ ├── .vitepress/
│ │ ├── config.mts # 配置文件
│ │ ├── theme/
│ │ │ ├── index.ts # 主题入口
│ │ │ ├── style.css # 自定义样式
│ │ │ └── components/ # 自定义组件
│ │ └── cache/ # 缓存目录(自动生成)
│ ├── public/ # 静态资源
│ │ ├── logo.svg
│ │ └── favicon.ico
│ ├── guide/
│ │ ├── index.md # /guide/
│ │ ├── getting-started.md # /guide/getting-started
│ │ └── advanced.md # /guide/advanced
│ ├── api/
│ │ └── index.md # /api/
│ └── index.md # 首页
├── package.json
└── tsconfig.json
路由规则
VitePress 使用基于文件的路由:
| 文件路径 | 对应 URL |
docs/index.md | / |
docs/guide/index.md | /guide/ |
docs/guide/getting-started.md | /guide/getting-started |
docs/api/reference.md | /api/reference |
特殊目录说明
.vitepress/ - VitePress 配置和主题文件
.vitepress/cache/ - 开发缓存,可添加到 .gitignore
.vitepress/dist/ - 构建输出目录
public/ - 静态资源,会原样复制到输出目录
配置详解
基础配置
创建 .vitepress/config.mts 文件:
import { defineConfig } from 'vitepress'
export default defineConfig({
title: 'My Awesome Docs',
description: 'A VitePress Site',
lang: 'zh-CN',
base: '/',
outDir: './.vitepress/dist',
cacheDir: './.vitepress/cache',
srcDir: './',
cleanUrls: true,
lastUpdated: true,
head: [
['link', { rel: 'icon', href: '/favicon.ico' }],
['meta', { name: 'theme-color', content: '#3c8772' }],
['meta', { name: 'og:type', content: 'website' }],
['meta', { name: 'og:locale', content: 'zh_CN' }],
],
})
主题配置
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
logo: '/logo.svg',
siteTitle: 'My Docs',
nav: [
{ text: '指南', link: '/guide/' },
{ text: 'API', link: '/api/' },
{
text: '更多',
items: [
{ text: '更新日志', link: '/changelog' },
{ text: '贡献指南', link: '/contributing' },
]
},
{
text: '版本',
items: [
{ text: 'v1.x', link: '/v1/' },
{ text: 'v2.x (当前)', link: '/' },
]
}
],
sidebar: {
'/guide/': [
{
text: '入门',
collapsed: false,
items: [
{ text: '简介', link: '/guide/' },
{ text: '快速开始', link: '/guide/getting-started' },
{ text: '配置', link: '/guide/configuration' },
]
},
{
text: '进阶',
collapsed: false,
items: [
{ text: '主题定制', link: '/guide/theme' },
{ text: '部署', link: '/guide/deploy' },
]
}
],
'/api/': [
{
text: 'API 参考',
items: [
{ text: '配置', link: '/api/config' },
{ text: '运行时 API', link: '/api/runtime' },
]
}
]
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/username/repo' },
{ icon: 'twitter', link: 'https://twitter.com/username' },
{ icon: 'discord', link: 'https://discord.gg/invite' },
],
footer: {
message: 'Released under the MIT License.',
copyright: 'Copyright © 2024-present My Team'
},
editLink: {
pattern: 'https://github.com/username/repo/edit/main/docs/:path',
text: '在 GitHub 上编辑此页'
},
lastUpdated: {
text: '最后更新于',
formatOptions: {
dateStyle: 'short',
timeStyle: 'short'
}
},
docFooter: {
prev: '上一页',
next: '下一页'
},
outline: {
level: [2, 3],
label: '本页目录'
},
returnToTopLabel: '返回顶部',
sidebarMenuLabel: '菜单',
darkModeSwitchLabel: '主题',
lightModeSwitchTitle: '切换到浅色模式',
darkModeSwitchTitle: '切换到深色模式',
}
})
Frontmatter 配置
每个 Markdown 文件可以使用 YAML frontmatter 进行页面级配置:
---
title: 页面标题
description: 页面描述
layout: doc
aside: true
outline: [2, 3]
lastUpdated: true
layout: home
hero:
name: My Project
text: 快速构建现代文档
tagline: 基于 Vite & Vue 的静态站点生成器
image:
src: /logo.svg
alt: Logo
actions:
- theme: brand
text: 快速开始
link: /guide/getting-started
- theme: alt
text: GitHub
link: https://github.com/username/repo
features:
- icon: ⚡️
title: 极速体验
details: 基于 Vite 的即时服务器启动和闪电般的热更新
- icon: 🖖
title: Vue 驱动
details: 在 Markdown 中使用 Vue 组件,享受 Vue 的强大功能
- icon: 🛠️
title: 简单易用
details: 以最少的配置快速构建美观的文档站点
---
自定义首页
---
layout: home
hero:
name: VitePress
text: Vite & Vue 驱动的静态站点生成器
tagline: 简单、强大、快速
image:
src: /logo-large.svg
alt: VitePress
actions:
- theme: brand
text: 快速开始
link: /guide/getting-started
- theme: alt
text: 在 GitHub 上查看
link: https://github.com/vuejs/vitepress
features:
- icon: 📝
title: 专注于内容
details: 只需使用 Markdown 即可轻松创建美观的文档站点
- icon: <svg xmlns="http://www.w3.org/2000/svg" width="32" viewBox="0 0 256 220.8"><path fill="#41B883" d="..."/></svg>
title: 享受 Vite 体验
details: 即时服务器启动、闪电般的热更新,以及基于 Rollup 的优化构建
- icon:
src: /custom-icon.svg
title: 高度可定制
details: 通过 Vite 插件和 Vue 组件扩展你的站点
---
Markdown 扩展
VitePress 在标准 Markdown 基础上提供了丰富的扩展功能。
内部链接
[快速开始](./getting-started.md)
[API 参考](../api/index.md)
[首页](/index.md)
[指南](/guide/)
[配置详解](#配置详解)
[其他页面的锚点](./other-page.md#section)
代码块增强
语法高亮
VitePress 使用 Shiki 进行代码高亮,支持几乎所有编程语言。
interface User {
id: number
name: string
email: string
}
function greet(user: User): string {
return `Hello, ${user.name}!`
}
行高亮
import { defineConfig } from 'vitepress'
export default defineConfig({
title: 'My Docs',
description: 'A VitePress Site',
lang: 'zh-CN',
})
语法:在语言标识符后添加 {行号} 或 {起始行-结束行}
```typescript{1,4-6}
// 高亮第 1 行和第 4-6 行
行号显示
在配置中启用:
export default defineConfig({
markdown: {
lineNumbers: true
}
})
或在单个代码块中启用:
```typescript:line-numbers
// 显示行号
代码聚焦
使用 // [!code focus] 注释聚焦特定行:
export default defineConfig({
title: 'My Docs',
description: 'A VitePress Site',
})
差异对比
使用 // [!code ++] 和 // [!code --] 显示代码差异:
export default {
data() {
return {
msg: 'Removed'
msg: 'Added'
}
}
}
错误和警告高亮
export default {
data() {
return {
msg: 'Error highlighted'
msg: 'Warning highlighted'
}
}
}
代码组
- 使用
:::code-group 创建多标签代码块:
-
:: code-group
:::
语法:
::: code-group
```bash [npm]
npm install vitepress
:::
### 自定义容器
VitePress 支持多种提示容器:
::: info 信息
这是一条信息提示
:::
::: tip 提示
这是一条友好的提示
:::
::: warning 警告
这是一条警告信息
:::
::: danger 危险
这是一条危险警告
:::
::: details 点击查看详情
这是折叠的详细内容
:::
语法:
```markdown
::: info 信息
这是一条信息提示
:::
::: tip 提示
这是一条友好的提示
:::
::: warning 警告
这是一条警告信息
:::
::: danger 危险
这是一条危险警告
:::
::: details 点击查看详情
这是折叠的详细内容
:::
GitHub 风格的告警
VitePress 也支持 GitHub 风格的告警语法:
> [!NOTE]
> 强调用户应该注意的信息
> [!TIP]
> 帮助用户更好地完成任务的建议
> [!IMPORTANT]
> 用户成功完成任务所需的关键信息
> [!WARNING]
> 可能导致问题的紧急信息
> [!CAUTION]
> 某些操作可能带来的负面后果
表格
| 功能 | 支持情况 | 备注 |
| 左对齐 | ✅ | 使用 :--- |
| 居中对齐 | ✅ | 使用 :---: |
| 右对齐 | ✅ | 使用 ---: |
Emoji
VitePress 支持 Emoji 表情:
效果::tada: :100: :rocket:
目录生成
在任意位置插入 [[toc]] 会生成当前页面的目录:
数学公式
VitePress 支持 LaTeX 数学公式(需要配置):
export default defineConfig({
markdown: {
math: true
}
})
行内公式:E = mc^2
块级公式:
\frac{d}{dx}\left( \int_{0}^{x} f(u)\,du\right)=f(x)
图片懒加载
export default defineConfig({
markdown: {
image: {
lazyLoading: true
}
}
})
主题定制
自定义 CSS
创建 .vitepress/theme/style.css:
:root {
--vp-c-brand-1: #5b8dfe;
--vp-c-brand-2: #3c70dc;
--vp-c-brand-3: #2655b8;
--vp-c-brand-soft: rgba(91, 141, 254, 0.14);
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: linear-gradient(
120deg,
#5b8dfe 30%,
#41d1ff
);
--vp-home-hero-image-background-image: linear-gradient(
-45deg,
#5b8dfe 50%,
#41d1ff 50%
);
--vp-home-hero-image-filter: blur(44px);
}
.dark {
--vp-c-brand-1: #7aa2ff;
--vp-c-brand-2: #5b8dfe;
--vp-c-brand-3: #3c70dc;
}
:root {
--vp-font-family-base: 'Inter', 'Chinese Quotes', 'Inter', ui-sans-serif,
system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
'Helvetica Neue', Helvetica, Arial, 'Noto Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--vp-font-family-mono: 'JetBrains Mono', 'Fira Code', ui-monospace,
SFMono-Regular, 'SF Mono', Menlo, Monaco, Consolas, 'Liberation Mono',
'Courier New', monospace;
}
.vp-doc div[class*='language-'] {
border-radius: 8px;
}
.vp-doc div[class*='language-'] > span.lang {
display: none;
}
.vp-doc a {
text-decoration: none;
border-bottom: 1px solid var(--vp-c-brand-1);
transition: border-color 0.25s;
}
.vp-doc a:hover {
border-bottom-color: transparent;
}
主题入口文件
创建 .vitepress/theme/index.ts:
import { h } from 'vue'
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import './style.css'
import MyComponent from './components/MyComponent.vue'
export default {
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
'nav-bar-title-before': () => h('span', 'Before'),
'nav-bar-title-after': () => h('span', 'After'),
'nav-bar-content-before': () => h(MyComponent),
'nav-bar-content-after': () => h('div', 'After Nav'),
'sidebar-nav-before': () => h('div', 'Sidebar Top'),
'sidebar-nav-after': () => h('div', 'Sidebar Bottom'),
'doc-before': () => h('div', 'Before Doc'),
'doc-after': () => h('div', 'After Doc'),
'doc-footer-before': () => h('div', 'Before Footer'),
'layout-bottom': () => h('div', 'Layout Bottom'),
})
},
enhanceApp({ app, router, siteData }) {
app.component('MyComponent', MyComponent)
router.onBeforeRouteChange = (to) => {
console.log('路由即将改变到:', to)
}
router.onAfterRouteChanged = (to) => {
console.log('路由已改变到:', to)
}
},
setup() {
}
} satisfies Theme
可用的布局插槽
VitePress 默认主题提供了以下布局插槽:
| 插槽名称 | 位置说明 |
layout-top | 布局最顶部 |
layout-bottom | 布局最底部 |
nav-bar-title-before | 导航栏标题之前 |
nav-bar-title-after | 导航栏标题之后 |
nav-bar-content-before | 导航栏菜单之前 |
nav-bar-content-after | 导航栏菜单之后 |
nav-screen-content-before | 移动端菜单内容之前 |
nav-screen-content-after | 移动端菜单内容之后 |
sidebar-nav-before | 侧边栏顶部 |
sidebar-nav-after | 侧边栏底部 |
aside-top | 右侧边栏顶部 |
aside-bottom | 右侧边栏底部 |
aside-outline-before | 大纲之前 |
aside-outline-after | 大纲之后 |
aside-ads-before | 广告位之前 |
aside-ads-after | 广告位之后 |
doc-top | 文档页面顶部 |
doc-bottom | 文档页面底部 |
doc-before | 文档内容之前 |
doc-after | 文档内容之后 |
doc-footer-before | 文档页脚之前 |
not-found | 404 页面内容 |
home-hero-before | 首页 Hero 之前 |
home-hero-after | 首页 Hero 之后 |
home-hero-info | 首页 Hero 信息区域 |
home-hero-image | 首页 Hero 图片区域 |
home-features-before | 首页特性之前 |
home-features-after | 首页特性之后 |
自定义组件
在 Markdown 中使用 Vue 组件
VitePress 允许在 Markdown 文件中直接使用 Vue 组件。
全局组件
在主题入口文件中注册:
import MyButton from './components/MyButton.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('MyButton', MyButton)
}
}
在 Markdown 中使用:
局部组件
在 Markdown 文件中直接导入:
<script setup>
import CustomDemo from '../components/CustomDemo.vue'
</script>
# 我的页面
下面是一个自定义组件:
<CustomDemo />
常用组件示例
徽章组件
创建 .vitepress/theme/components/Badge.vue:
<script setup lang="ts">
defineProps<{
text: string
type?: 'info' | 'tip' | 'warning' | 'danger'
}>()
</script>
<template>
<span class="badge" :class="type">
{{ text }}
</span>
</template>
<style scoped>
.badge {
display: inline-block;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
line-height: 1.5;
}
.info {
background-color: var(--vp-c-info-soft);
color: var(--vp-c-info-1);
}
.tip {
background-color: var(--vp-c-tip-soft);
color: var(--vp-c-tip-1);
}
.warning {
background-color: var(--vp-c-warning-soft);
color: var(--vp-c-warning-1);
}
.danger {
background-color: var(--vp-c-danger-soft);
color: var(--vp-c-danger-1);
}
</style>
代码演示组件
创建 .vitepress/theme/components/CodeDemo.vue:
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{
title?: string
}>()
const showCode = ref(false)
</script>
<template>
<div class="code-demo">
<div class="demo-header">
<span class="title">{{ title || '示例' }}</span>
<button @click="showCode = !showCode">
{{ showCode ? '隐藏代码' : '查看代码' }}
</button>
</div>
<div class="demo-preview">
<slot name="preview" />
</div>
<div v-show="showCode" class="demo-code">
<slot name="code" />
</div>
</div>
</template>
<style scoped>
.code-demo {
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
margin: 16px 0;
overflow: hidden;
}
.demo-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background-color: var(--vp-c-bg-soft);
border-bottom: 1px solid var(--vp-c-divider);
}
.title {
font-weight: 600;
font-size: 14px;
}
.demo-header button {
padding: 4px 12px;
border: 1px solid var(--vp-c-brand-1);
border-radius: 4px;
background: transparent;
color: var(--vp-c-brand-1);
cursor: pointer;
font-size: 12px;
}
.demo-header button:hover {
background-color: var(--vp-c-brand-soft);
}
.demo-preview {
padding: 24px;
}
.demo-code {
border-top: 1px solid var(--vp-c-divider);
}
.demo-code :deep(div[class*='language-']) {
margin: 0;
border-radius: 0;
}
</style>
使用 VitePress 内置组件
VitePress 提供了一些内置组件:
VPTeamMembers
展示团队成员:
<script setup>
import { VPTeamMembers } from 'vitepress/theme'
const members = [
{
avatar: 'https://github.com/yyx990803.png',
name: 'Evan You',
title: 'Creator',
links: [
{ icon: 'github', link: 'https://github.com/yyx990803' },
{ icon: 'twitter', link: 'https://twitter.com/youyuxi' }
]
},
]
</script>
# 我们的团队
<VPTeamMembers size="small" :members="members" />
ClientOnly
包裹只在客户端渲染的组件:
<ClientOnly>
<NonSSRFriendlyComponent />
</ClientOnly>
国际化 (i18n)
配置多语言
import { defineConfig } from 'vitepress'
export default defineConfig({
locales: {
root: {
label: '简体中文',
lang: 'zh-CN',
link: '/',
themeConfig: {
nav: [
{ text: '指南', link: '/guide/' },
],
sidebar: {
'/guide/': [
{ text: '快速开始', link: '/guide/getting-started' }
]
},
docFooter: {
prev: '上一页',
next: '下一页'
},
outline: {
label: '本页目录'
},
lastUpdated: {
text: '最后更新于'
},
editLink: {
pattern: 'https://github.com/user/repo/edit/main/docs/:path',
text: '在 GitHub 上编辑此页'
}
}
},
en: {
label: 'English',
lang: 'en',
link: '/en/',
themeConfig: {
nav: [
{ text: 'Guide', link: '/en/guide/' },
],
sidebar: {
'/en/guide/': [
{ text: 'Getting Started', link: '/en/guide/getting-started' }
]
},
docFooter: {
prev: 'Previous',
next: 'Next'
},
outline: {
label: 'On this page'
},
lastUpdated: {
text: 'Last updated'
},
editLink: {
pattern: 'https://github.com/user/repo/edit/main/docs/:path',
text: 'Edit this page on GitHub'
}
}
}
}
})
目录结构
docs/
├── index.md # 中文首页 (/)
├── guide/
│ ├── index.md # 中文指南 (/guide/)
│ └── getting-started.md
├── en/
│ ├── index.md # 英文首页 (/en/)
│ └── guide/
│ ├── index.md # 英文指南 (/en/guide/)
│ └── getting-started.md
└── .vitepress/
└── config.mts
语言切换组件
VitePress 会自动在导航栏显示语言切换器。你也可以使用 useData 组合式函数获取当前语言:
<script setup>
import { useData } from 'vitepress'
const { lang, site, page, frontmatter, localeIndex } = useData()
</script>
<template>
<p>当前语言: {{ lang }}</p>
<p>语言索引: {{ localeIndex }}</p>
</template>
搜索功能
本地搜索
VitePress 内置了本地全文搜索功能:
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
locales: {
zh: {
translations: {
button: {
buttonText: '搜索文档',
buttonAriaLabel: '搜索文档'
},
modal: {
noResultsText: '无法找到相关结果',
resetButtonTitle: '清除查询条件',
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭'
}
}
}
}
},
_render(src, env, md) {
const html = md.render(src, env)
if (env.frontmatter?.search === false) {
return ''
}
return html
}
}
}
}
})
Algolia DocSearch
对于大型文档站点,推荐使用 Algolia DocSearch:
export default defineConfig({
themeConfig: {
search: {
provider: 'algolia',
options: {
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'YOUR_INDEX_NAME',
locales: {
zh: {
placeholder: '搜索文档',
translations: {
button: {
buttonText: '搜索',
buttonAriaLabel: '搜索'
},
modal: {
searchBox: {
resetButtonTitle: '清除查询条件',
resetButtonAriaLabel: '清除查询条件',
cancelButtonText: '取消',
cancelButtonAriaLabel: '取消'
},
startScreen: {
recentSearchesTitle: '搜索历史',
noRecentSearchesText: '没有搜索历史',
saveRecentSearchButtonTitle: '保存至搜索历史',
removeRecentSearchButtonTitle: '从搜索历史中移除',
favoriteSearchesTitle: '收藏',
removeFavoriteSearchButtonTitle: '从收藏中移除'
},
errorScreen: {
titleText: '无法获取结果',
helpText: '你可能需要检查你的网络连接'
},
footer: {
selectText: '选择',
navigateText: '切换',
closeText: '关闭',
searchByText: '搜索提供者'
},
noResultsScreen: {
noResultsText: '无法找到相关结果',
suggestedQueryText: '你可以尝试查询',
reportMissingResultsText: '你认为该查询应该有结果?',
reportMissingResultsLinkText: '点击反馈'
}
}
}
}
}
}
}
}
})
部署指南
构建项目
构建输出默认位于 .vitepress/dist 目录。
预览构建产物
部署到不同平台
GitHub Pages
- 在
config.mts 中设置正确的 base:
export default defineConfig({
base: '/your-repo-name/'
})
- 创建
.github/workflows/deploy.yml:
name: Deploy VitePress site to GitHub Pages
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Install dependencies
run: npm ci
- name: Build with VitePress
run: npm run docs:build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: docs/.vitepress/dist
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
needs: build
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
Netlify
- 创建
netlify.toml:
[build]
command = "npm run docs:build"
publish = "docs/.vitepress/dist"
[build.environment]
NODE_VERSION = "20"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
Vercel
- 创建
vercel.json:
{
"buildCommand": "npm run docs:build",
"outputDirectory": "docs/.vitepress/dist",
"framework": "vitepress"
}
Cloudflare Pages
- 在 Cloudflare Pages 控制台设置:
- 构建命令:
npm run docs:build
- 输出目录:
docs/.vitepress/dist
- Node.js 版本:
20
Docker
创建 Dockerfile:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run docs:build
FROM nginx:alpine
COPY --from=builder /app/docs/.vitepress/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
创建 nginx.conf:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
1y;
Cache-Control "public, immutable";
}
}
性能优化
1. 启用 MPA 模式
对于大型文档站点,可以考虑启用 MPA(多页面应用)模式:
export default defineConfig({
mpa: true
})
2. 配置资源预加载
export default defineConfig({
head: [
['link', { rel: 'dns-prefetch', href: 'https://fonts.gstatic.com' }],
['link', { rel: 'preconnect', href: 'https://fonts.googleapis.com' }],
]
})
3. 图片优化
export default defineConfig({
markdown: {
image: {
lazyLoading: true
}
}
})
4. 代码分割
VitePress 默认会对页面进行代码分割。对于自定义组件,可以使用动态导入:
<script setup>
import { defineAsyncComponent } from 'vue'
const HeavyComponent = defineAsyncComponent(() =>
import('./components/HeavyComponent.vue')
)
</script>
5. 限制搜索索引范围
export default defineConfig({
themeConfig: {
search: {
provider: 'local',
options: {
miniSearch: {
searchOptions: {
fuzzy: 0.2,
prefix: true,
boost: { title: 4, text: 2, titles: 1 }
}
}
}
}
}
})
6. 缓存配置
export default defineConfig({
cacheDir: './.vitepress/cache',
vite: {
build: {
chunkSizeWarningLimit: 500
}
}
})
最佳实践
1. 目录组织
docs/
├── index.md # 首页
├── guide/ # 用户指南
│ ├── index.md
│ ├── getting-started.md
│ └── ...
├── api/ # API 文档
│ ├── index.md
│ └── ...
├── examples/ # 示例
│ └── ...
├── blog/ # 博客(可选)
│ └── ...
├── public/ # 静态资源
│ ├── images/
│ ├── logo.svg
│ └── favicon.ico
└── .vitepress/
├── config.mts # 主配置文件
├── theme/
│ ├── index.ts # 主题入口
│ ├── style.css # 自定义样式
│ └── components/ # 自定义组件
└── cache/ # 缓存目录
2. 配置文件拆分
对于大型项目,可以拆分配置:
import { defineConfig } from 'vitepress'
import { nav } from './configs/nav'
import { sidebar } from './configs/sidebar'
import { head } from './configs/head'
export default defineConfig({
title: 'My Docs',
description: 'A VitePress Site',
head,
themeConfig: {
nav,
sidebar,
}
})
import type { DefaultTheme } from 'vitepress'
export const nav: DefaultTheme.NavItem[] = [
{ text: '指南', link: '/guide/' },
{ text: 'API', link: '/api/' },
]
import type { DefaultTheme } from 'vitepress'
export const sidebar: DefaultTheme.Sidebar = {
'/guide/': [
{
text: '入门',
items: [
{ text: '简介', link: '/guide/' },
{ text: '快速开始', link: '/guide/getting-started' },
]
}
]
}
3. Markdown 写作规范
- 使用语义化的标题层级(h1 仅用于页面标题)
- 使用适当的代码块语言标识
- 为所有图片添加 alt 文本
- 使用相对链接引用其他文档
- 利用 Frontmatter 设置页面元数据
4. Git 忽略配置
添加到 .gitignore:
# VitePress
docs/.vitepress/cache
docs/.vitepress/dist
node_modules
# 本地环境
.env.local
*.local
5. TypeScript 配置
创建 tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "preserve",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"types": ["vitepress/client"],
"paths": {
"@/*": ["./docs/.vitepress/*"]
}
},
"include": ["docs/.vitepress/**/*.ts", "docs/.vitepress/**/*.vue"],
"exclude": ["node_modules"]
}
6. 运行时数据与构建时数据
VitePress 提供了强大的数据加载功能:
构建时数据加载
创建 .vitepress/theme/loaders/data.data.ts:
import { createContentLoader } from 'vitepress'
export default createContentLoader('blog/**/*.md', {
excerpt: true,
transform(rawData) {
return rawData
.sort((a, b) => {
return +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date)
})
.map(page => ({
title: page.frontmatter.title,
url: page.url,
date: page.frontmatter.date,
excerpt: page.excerpt
}))
}
})
在组件中使用:
<script setup>
import { data as posts } from '../loaders/data.data'
</script>
<template>
<div v-for="post in posts" :key="post.url">
<a :href="post.url">{{ post.title }}</a>
<span>{{ post.date }}</span>
</div>
</template>
运行时数据访问
<script setup>
import { useData, useRoute, useRouter } from 'vitepress'
const { site, page, frontmatter, lang, theme } = useData()
const route = useRoute()
const router = useRouter()
console.log(page.value.title)
console.log(frontmatter.value)
router.go('/guide/')
</script>
高级扩展
Vite 插件集成
import { defineConfig } from 'vitepress'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
import Icons from 'unplugin-icons/vite'
export default defineConfig({
vite: {
plugins: [
Components({
dirs: ['docs/.vitepress/theme/components'],
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
}),
AutoImport({
imports: ['vue', '@vueuse/core'],
}),
Icons({
autoInstall: true,
}),
],
optimizeDeps: {
include: ['vue', '@vueuse/core'],
exclude: ['vitepress']
},
server: {
port: 5173,
host: true,
},
build: {
chunkSizeWarningLimit: 1000,
rollupOptions: {
output: {
manualChunks: {
'vue-vendor': ['vue', 'vue-router'],
}
}
}
}
}
})
PWA 支持
安装依赖:
npm install -D @vite-pwa/vitepress
配置:
import { defineConfig } from 'vitepress'
import { withPwa } from '@vite-pwa/vitepress'
export default withPwa(
defineConfig({
title: 'My Docs',
pwa: {
mode: 'development',
registerType: 'autoUpdate',
includeAssets: ['favicon.ico', 'logo.svg'],
manifest: {
name: 'My Documentation',
short_name: 'MyDocs',
theme_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
],
},
workbox: {
globPatterns: ['**/*.{css,js,html,svg,png,ico,txt,woff2}'],
},
},
})
)
自定义 Markdown 渲染
import { defineConfig } from 'vitepress'
import markdownItFootnote from 'markdown-it-footnote'
import markdownItTaskLists from 'markdown-it-task-lists'
export default defineConfig({
markdown: {
lineNumbers: true,
math: true,
theme: {
light: 'github-light',
dark: 'github-dark'
},
image: {
lazyLoading: true
},
anchor: {
permalink: true,
permalinkSymbol: '#',
permalinkBefore: true
},
config: (md) => {
md.use(markdownItFootnote)
md.use(markdownItTaskLists)
const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options)
}
md.renderer.rules.link_open = function(tokens, idx, options, env, self) {
const token = tokens[idx]
const href = token.attrGet('href')
if (href && href.startsWith('http')) {
token.attrSet('target', '_blank')
token.attrSet('rel', 'noopener noreferrer')
}
return defaultRender(tokens, idx, options, env, self)
}
}
}
})
故障排除
常见问题
1. 构建失败:内存不足
NODE_OPTIONS=--max-old-space-size=8192 npm run docs:build
2. 开发服务器热更新失效
检查文件监听限制:
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
3. 图片无法显示
确保图片路径正确:



4. 代码高亮不生效
确保使用正确的语言标识符:
#### 5. 自定义组件未生效
确保组件已正确注册:
```typescript
// .vitepress/theme/index.ts
import MyComponent from './components/MyComponent.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('MyComponent', MyComponent)
}
}
参考资料
本文持续更新中,如有问题或建议,欢迎反馈。
请先登录后再发表评论