跳转到内容

VitePress — Vue 团队用 Vite 写的静态文档站点生成器

是什么

VitePress 是把 markdown 直接变成静态 HTML 站点的工具,专门给”写文档”这件事设计,由 Vue 团队维护。日常类比:像一个会自己排版的印刷机——你写文字稿(markdown),它帮你印成一本电子书(带导航、搜索、代码高亮的网站)。

你写:

# 我的文档
这里是一段说明,下面有代码:
```js
console.log('hello')
跑一行 `npx vitepress build`,VitePress 把这份 .md 转成 .html,附上侧边栏、深色模式、代码高亮、自动生成的目录——一个标准文档站就出来了。
Vue 自己的官网、Pinia、Vitest、VueUse 的文档全部用 VitePress 写——**它就是 Vue 生态脚下的那块地板**。
## 为什么重要
不理解 VitePress 长啥样,下面这些事都会困惑:
- 为什么 docs 站点首屏那么轻——它把"99% 是静态 HTML"这个事实做到了字节级别
- 为什么写文档可以**直接在 markdown 里塞 Vue 组件**——不用 MDX 那种 JSX-flavored 语法
- 为什么 Vue 团队会做 Astro / Docusaurus / Nextra 之外的第四种选择——心智不同
- 为什么 dev server 启动几乎瞬时——Vite 的 ESM 原生 + HMR 已经赢了
## 核心要点
VitePress 把"docs 站点"拆成 **三个心脏**:
1. **markdown 转换器**:底下用社区成熟的 markdown-it(async 分支),上面挂 17 个插件按顺序拼出"VitePress 风味"——`:::tip`、`<<< @/file.ts` 引用、shiki 代码高亮、GitHub Alerts 这些都是插件做的。类比:一条流水线,原料从一头进去,每个工位贴一个加工。
2. **双 bundle SSG 构建**:跑两次 Vite build——一次 **client**(输出浏览器要的 JS/CSS),一次 **server**(输出 SSR render 函数)。同一份源码经过 Vite plugin 自动变两套产物,VitePress 自己不写 SSG 引擎,把活外包给 Vite。
3. **lean + full 双客户端 bundle**:第一次访问页面只下载 `.lean.js`(hydration 必需的最小代码),从这页跳走再回来才下载 `.full.js`(带完整组件交互逻辑)。类比:进门只发名片,要谈合作再拿合同——首屏 JS 减 30-50%。
三件加起来才 ~6k 行 TypeScript(不含默认主题的 .vue),是"框架做减法"的代表作。
## 实践案例
### 案例 1:60 秒起一个 docs 站
```bash
mkdir my-docs && cd my-docs
npm init -y
npm install -D vitepress
npx vitepress init
# 选 ./docs / Site title: Test / Default theme
npm run docs:dev # 起 dev server 在 http://localhost:5173
npm run docs:build # 输出 docs/.vitepress/dist
ls docs/.vitepress/dist/assets/chunks/
# index.<hash>.js index.<hash>.lean.js ← 双 bundle 验证

hashmap.json 是每页 → 内容 hash 的映射,给”用户停在旧版本,你刚部署新版本”做兜底重拉。

案例 2:在 markdown 里直接用 Vue 组件

.vitepress/theme/index.ts

import DefaultTheme from 'vitepress/theme'
import Counter from './Counter.vue'
export default {
extends: DefaultTheme,
enhanceApp({ app }) {
app.component('Counter', Counter)
}
}

然后任何 .md 里直接 <Counter :start="3" /> 就能用。enhanceApp 是用户唯一能”插进 Vue runtime”的扩展点——错过它就只能改默认主题源码。

案例 3:自己写 markdown-it 插件加新语法

.vitepress/config.ts

export default defineConfig({
markdown: {
config(md) {
md.use((md) => {
md.core.ruler.push('my-marker', (state) => {
// 自定义 token 处理
})
})
}
}
})

config(md) 在 VitePress 自己 17 个插件之后跑(用户最后说话),还有个 preConfig(md) 在所有插件之前跑(少见场景)。

踩过的坑

  1. lean / full 双 bundle 的切换由 isInitialPageLoad 驱动:这个标志在 client/app/index.ts 模块级,只在 inBrowser 时重置——SSR 自定义 runner 复用 createApp 时不会清零,后续路由会一直拿 lean 失败

  2. createMarkdownRenderer 是单例if (md) return md 让同一 node 进程只创一个实例。monorepo nx 缓存复用 node worker 时,shiki 主题切换可能不生效——只在 dev server 重启时调 disposeMdItInstance()

  3. 17 个 markdown-it 插件的注册顺序就是语义componentPlugin 必须最先(识别 Vue 组件标记,避免被 markdown 转义成 <p>),snippetPlugin 必须在 preWrapperPlugin 之前——颠倒会让代码块外壳包错

  4. enhanceApp 钩子很容易漏写:用户经常把全局组件直接 import 到 .md 文件,导致 SSR 报错 window is not defined——必须在 enhanceAppapp.component() 注册,VitePress 会自动包 <ClientOnly> 兜底

适用 vs 不适用场景

适用

  • Vue 生态的产品 / 库文档(与 Vue 组件天然衔接)
  • markdown 占 80% 内容、需要少量交互的技术博客
  • 想要极致首屏性能的 docs 站(lean bundle 拍平了 SPA framework 的开销)
  • 对 dev 体验敏感的写作场景(HMR 毫秒级回显)

不适用

  • React / Solid / Svelte 生态项目 → 用 Docusaurus / Nextra / Starlight
  • 内容动态化重的站点(需要 CMS / SSR fetch)→ 用 Nuxt / Next
  • 不写 markdown 的纯 SPA → 直接用 Vite + Vue
  • 需要 MDX 那种 JSX-in-markdown 的项目 → VitePress 用的是 SFC 风格不是 JSX

历史小故事(可跳过)

  • 2018 年:尤雨溪写 VuePress(webpack 底,Vue 2),Vue 官网在它身上痛苦了 4 年——启动慢、HMR 重、依赖一长串自家 plugin
  • 2020 年:尤雨溪做 Vite(“另起炉灶比改 webpack 容易”),同年 11 月 Vite 1.0 发布
  • 2021 年:顺手起了 VitePress 这个”用 Vite 重写 VuePress”的实验项目——本意是给 Vue 3 文档用
  • 2024-03:VitePress 1.0 正式发布,成为 Vue 生态官方推荐
  • 2026 年:当前 2.0-alpha.17,brc-dd 接手主维护(979 commit),尤雨溪退到 second commiter(508 commit)

学到什么

  1. 框架的最高境界是做减法——VitePress 主仓只 ~6k 行 TS,因为 markdown 转换、build、SSR 全部外包给社区成熟工具
  2. “双 bundle”是 docs 站点的关键优化——lean 给首屏,full 给交互,这个分流让 docs 站点首屏字节数掉到一个量级
  3. markdown 转 Vue SFC 而不是发明新语法——这是 VitePress 与 MDX 的根本分歧。Vue SFC 已经是用户熟悉的容器,没必要再学 JSX-in-markdown
  4. 插件顺序即语义:17 个 markdown-it 插件的注册顺序决定了语法解析结果。顺序是 API 的一部分

延伸阅读

关联

  • vite —— Vite 提供 dev server / 双 build / Vite plugin 接口,VitePress 是 Vite 的”应用层用户”
  • vue —— VitePress 用 Vue 做 client runtime,markdown 转出来的就是 Vue SFC
  • markdown-it —— VitePress 的 markdown 内核,17 个插件全挂在它上面
  • shiki —— 代码高亮引擎,VitePress 用 shiki 双主题(light / dark)做语法着色
  • starlight —— Astro 生态的对应物,思路相似(markdown + 组件 + SSG)但底层引擎不同
  • docusaurus —— React 生态的对应物,Meta 维护,更重但功能更全
  • nextra —— Next.js 生态的对应物,MDX-first,VitePress 选了相反的 SFC-first 路线
  • rolldown —— Rust 写的 Rollup 替代品,VitePress 已支持 rolldown-vite

反向链接

  • astro —— Astro — 内容站点优先的 Web 框架
  • chalk —— chalk — 让 console.log 输出彩色字符串的 Node 库
  • dayjs —— Day.js — 用 2 KB 复刻 Moment 的极简日期库
  • docusaurus —— Docusaurus — 一组 plugin 协作出来的文档站框架
  • echarts —— Apache ECharts — 给一个 JSON 就能画图的可视化库
  • markdown-it —— markdown-it — 把 Markdown 文本变成 HTML 的工业级解析器
  • nextra —— Nextra — 在 Next.js 上盖一层文档站脚手架
  • rolldown —— rolldown — 用 Rust 给 Vite 当统一引擎的打包器
  • shiki —— shiki — 把 VS Code 那套染色搬到网页上
  • starlight —— Starlight — Astro 文档站点主题
  • vite —— Vite — 浏览器自己加载源码的构建工具
  • vue —— Vue.js — 渐进式 UI 框架
  • web-vitals —— web-vitals — 让你在自己页面测的数和 Google 排名用的数对得上