前言
最近整理之前的个人项目,比如 yuan-rtos 等,打算给他们写一些文档,详细描述它们有什么功能以及我是怎么实现的。
但是我觉得直接写一堆 Markdown 甩仓库里很难看,于是就开始找有没有什么比较好用的技术文档框架,最后找到了 VitePress。
学习并实际搭建了一个 VitePress 网站,接着部署到 GitHub Pages 后,我感觉效果还不错,写文档挺方便的,用起来也很省事。于是写这篇博客记录一下过程。
快速入门
VitePress 是什么?
VitePress 是 Vue 官方推出的静态站点生成器,基于 Vue 3 和 Vite 构建。核心思路很简单,用 Markdown 写内容,框架帮你生成一个文档网站。
它的特点:
- 零配置起步。安装后写一个
index.md就能跑起来,默认主题自带导航栏、侧边栏、搜索和明暗模式。 - 以内容为中心。每个 Markdown 文件就是一个页面,frontmatter 控制页面元数据和布局。
- 构建产物是纯静态文件。
dist目录可以直接扔到 GitHub Pages、Nginx 等任何静态托管平台。 - 可深度定制。默认主题基于 Vue 组件构建,可以像改普通 Vue 项目一样扩展它。
如果你需要的是开箱即用的文档站,而不是一套复杂的博客框架,VitePress 是很合适的选择。
启动你的第一个 VitePress 网站
前置条件很简单,机器上装好 Node.js 和 npm 就行。
创建或者打开一个专门用于写文档的文件夹,然后把 VitePress 安装为开发依赖:
npm add -D vitepress@next
接着使用 VitePress 附带的命令行设置向导,构建一个基本项目。命令如下:
npx vitepress init
初始化向导会询问站点名称、描述、主题风格等信息,我的选择如下:
┌ Welcome to VitePress!
│
◇ Where should VitePress initialize the config?
│ ./docs
│
◇ Where should VitePress look for your markdown files?
│ ./docs
│
◇ Site title:
│ My Awesome Project
│
◇ 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
│
◇ Add a prefix for VitePress npm scripts?
│ Yes
│
◇ Prefix for VitePress npm scripts:
│ docs
│
└ Done! Now run pnpm run docs:dev and start writing.
如果你拿不定主意,照着我选就行了,新手入门也不需要管那么多。如果你实在想知道什么意思,可以去翻阅官方手册。
最后,启动本地开发服务器:
npm run docs:dev
浏览器打开 http://localhost:5173(具体端口看终端日志里的实际输出,可能不一样),第一个本地网站就起来了。开发模式下改 Markdown 会热更新,保存即可看到效果。
路由机制
阅读官方文档的路由部分即可,这里不过多说明。
侧边栏怎么改
在 .vitepress/config.mts 中进行配置。
侧边栏配置在 themeConfig.sidebar 里,是一个数组,每个元素是一组分组,分组内可以继续嵌套子项。子项很多时可以用 collapsed: true 让它默认折叠。
示例如下:
import { defineConfig } from 'vitepress'
export default defineConfig({
themeConfig: {
sidebar: [
{
text: '项目简介',
items: [
{ text: '简介', link: '/introduction/' },
{ text: '优缺点', link: '/introduction/advantages-and-disadvantages' },
{ text: '安装', link: '/introduction/installation' },
]
},
{
text: 'Yuan RTOS 教程',
items: [
{
text: 'API 手册',
collapsed: true,
items: [
{ text: '总览与约定', link: '/tutorial/api/' },
// ...
]
}
]
}
]
}
})
详细说明见官方文档的侧边栏部分。
我设置侧边栏时遇到的上下页导航 Bug
把文档拆分到不同目录后,我发现一个问题,某些页面页脚的“上一页”与“下一页”的跳转不正常。
排查之后发现,原因出在配置里的链接写法。我最初在侧边栏里写的是:
{ text: '前言', link: '/preface' } // 少了末尾的斜杠
VitePress 内部会把 /preface/index.md 规范化为 /preface/,而当前页面路径是 /preface/。写 /preface 得到的字符串是 /preface,两者不相等,于是当前页匹配失败,页脚的前后页链接和侧边栏高亮就都不工作了。
修复很简单,目录首页的链接统一写成带尾斜杠的形式:
{ text: '前言', link: '/preface/' } // 目录首页必须带 /
普通文件页(如 /introduction/installation)不受影响,只有 index.md 对应的目录首页需要注意。
导航栏怎么改
在 .vitepress/config.mts 中进行配置。
导航栏是页面顶部的横向菜单,配置在 themeConfig.nav 里,每一项是一个 { text, link }:
nav: [
{ text: '首页', link: '/' },
{ text: '前言', link: '/preface/' },
{ text: '简介', link: '/introduction/' },
]
注意,目录首页的链接要带尾斜杠,具体原因在侧边栏一节下的 Bug 描述里说过。
详细说明见官方文档的导航栏部分。
主页怎么改
首页是 docs/index.md,通过 frontmatter 的 layout: home 开启首页布局,用 hero 配置大标题和按钮。
如果还想加特性卡片,在 frontmatter 里补 features 数组即可,每项 { icon, title, details }。
示例如下:
---
layout: home
hero:
name: "Yuan RTOS"
text: "轻量化 RTOS 编写指南"
tagline: 想要学习如何编写一个轻量化 RTOS 吗?在寻找一份新手友好的 RTOS 原理教程?那你可来对地方了!
actions:
- theme: brand
text: 开始阅读
link: /preface/
- theme: brand
text: 项目简介
link: /introduction/
- theme: alt
text: 前往仓库
link: https://github.com/DSJZS/yuan-rtos
features:
- title: 轻量级
details: 默认配置、-Os 优化下,内核仅增加约 640B RAM 与 2.5KB ROM,适合资源受限的 MCU。
- title: 实时调度
details: 32 级优先级的抢占式调度,配合时间片轮转;位图 + 双向循环链表实现 O(1) 就绪队列。
- title: 同步与通信
details: 信号量、递归互斥锁(支持优先级继承)、消息队列一应俱全,且都提供 ISR 安全版本。
- title: 时间管理
details: 基于系统 tick 的相对/周期延时与软件定时器,满足常见的超时与节拍需求。
- title: 可裁剪
details: 通过 yr_config.h 配置开关按需裁剪模块,没用到的功能不编译、不占资源。
- title: 可移植
details: 内核与移植层清晰分离,提供 Cortex-M3 + GCC 参考实现与 STM32F103 示例工程。
---
部署到 Github Pages
官方文档的部署部分详细记载了各平台如何部署。其中特别提到了如何部署到 GitHub Pages,写得很详细,点击链接快速跳转到对应的标题下查看,照着做就行了,非常简单。
值得说明的是,官方在这个文档中的设定 public 根目录标题下的内容也要看,内容如下:
默认情况下,我们假设站点将部署在域名 (/) 的根路径上。如果站点在子路径中提供服务,例如 https://mywebsite.com/blog/,则需要在 VitePress 配置中将 base 选项设置为 ‘/blog/’。
例:如果你使用的是 GitHub(或 GitLab)页面并部署到 user.github.io/repo/,请将 base 设置为 /repo/。
比如我的站点部署在 masterji.top/yuan-rtos/ 这个子路径下,而不是域名根路径,所以需要在配置里设置 base:
export default defineConfig({
// ...
base: '/yuan-rtos/'
})
如果不设置 base,构建出的静态资源会引用 /assets/...,部署到子路径后所有 CSS/JS 都会 404。域名根路径部署可以省略这项。
另外,docs/.vitepress/dist、cache、.temp 都是构建产物,记得写进 .gitignore,避免提交垃圾文件:
docs/.vitepress/dist
docs/.vitepress/cache
docs/.vitepress/.temp/
node_modules/
*.log
.DS_Store
Thumbs.db
评论区怎么加
giscus 是一个基于 GitHub Discussions 的评论系统,评论数据直接存在仓库的 Discussion 里,免费、无广告、无需数据库。
前置准备
在 GitHub 上确认三件事:
- 仓库是公开的。
- 仓库 Settings → Features 里开启了 Discussions。
- 安装了 giscus app,并且安装到了目标仓库。
第 3 点最容易出问题。如果你把 app 装到了别的账号,或者安装时只勾选了部分仓库,giscus.app 会一直提示该仓库不满足要求。
我排查时用 GitHub API 确认了仓库是公开的、Discussions 也开了,但 giscus 的服务端接口仍返回 giscus is not installed on this repository,就是 app 没装到这个仓库。到 app 配置页把 DSJZS/yuan-rtos 加进授权列表就好了。
获取仓库 ID 和分类 ID
打开 giscus.app,填入仓库名,选择语言、映射方式(pathname)和分类(建议 Announcements),页面底部会生成一段 <script>,其中有四个关键值:
data-repo="DSJZS/yuan-rtos"
data-repo-id="R_kgDOR-1uFg"
data-category="Announcements"
data-category-id="DIC_kwDOR-1uFs4DDtAC"
其中 repo-id 和 category-id 只需要抄进代码,它们是公开的 ID,不存在泄密问题。
安装官方 Vue 组件
giscus 官方提供了 Vue 组件库 @giscus/vue:
npm add -D @giscus/vue
不建议用第三方包装插件(如 vitepress-plugin-comment-with-giscus)。一是维护不活跃,二是直接使用官方组件加 VitePress 的插槽机制,更简单可控。
创建评论组件
新建 docs/.vitepress/theme/components/Giscus.vue:
<script setup lang="ts">
import Giscus from '@giscus/vue'
import { useData } from 'vitepress'
const { isDark, page } = useData()
</script>
<template>
<div class="giscus-wrapper">
<hr class="giscus-divider" />
<Giscus
:key="page.relativePath"
repo="DSJZS/yuan-rtos"
repo-id="R_kgDOR-1uFg"
category="Announcements"
category-id="DIC_kwDOR-1uFs4DDtAC"
mapping="pathname"
strict="0"
reactions-enabled="1"
emit-metadata="0"
input-position="bottom"
:theme="isDark ? 'dark' : 'light'"
lang="zh-CN"
loading="lazy"
/>
</div>
</template>
<style scoped>
.giscus-divider {
margin: 32px 0;
border: 0;
border-top: 1px solid var(--vp-c-divider);
}
</style>
挂载到主题布局
修改 docs/.vitepress/theme/index.ts:
import { h } from 'vue'
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'
import Giscus from './components/Giscus.vue'
import './style.css'
export default {
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
'doc-after': () => h(Giscus)
})
}
} satisfies Theme
其他实用配置
都是 VitePress 提供的一些功能,浏览官方手册的配置与 API 参考可以找到更多。
显示最后更新事件
根级开启 lastUpdated: true,再在 themeConfig 里自定义文案和格式:
export default defineConfig({
lastUpdated: true,
themeConfig: {
lastUpdated: {
text: '最后更新于',
formatOptions: {
dateStyle: 'short',
timeStyle: 'short'
}
}
}
})
注意,这个时间来自 git 提交历史,所以 CI 构建时必须用 fetch-depth: 0 拉取完整历史,否则构建机上没有时间戳可读。
text 不写的话默认为 Last updated。
编辑链接
themeConfig: {
editLink: {
pattern: 'https://github.com/DSJZS/yuan-rtos/edit/main/docs/:path',
text: '在 GitHub 上编辑此页'
}
}
pattern 必须是完整的 URL,docs/:path 前要带上仓库地址。我一开始写成 pattern: '/docs/:path',结果生成的链接变成了站内相对路径,点击后 404,这是新手很容易忽略的一点。
text 不写的话默认为 Edit this page。
本地搜索
themeConfig: {
search: {
provider: 'local'
}
}
VitePress 内置的本地搜索无需额外安装,开箱即用。
结语
到这里,一个完整的 VitePress 文档站就搭好了,包括本地开发、导航侧边栏配置、GitHub Pages 自动部署、giscus 评论,以及最后更新时间和编辑链接这些小细节。整个过程没有引入任何复杂的构建工具,Markdown 写内容,配置文件调样式,剩下的交给 VitePress 和 GitHub Actions。