用VuePress搭建技术博客的实战经验与常见坑点总结
先看效果,再看代码
上周给团队搭内部文档站,选了 VuePress 2.x(不是 VuePress 1,别问,问就是 Vue 3 生态必须跟上)。我直接用 pnpm create vuepress@latest 初始化,选了 TypeScript + 默认主题 + Git 插件,5 分钟就跑起来了。首页是 markdown 写的 README.md,侧边栏自动从 sidebar.ts 读取,没配路由、没写入口文件——这玩意儿真不是“前端版 Markdown 博客生成器”,它是“Vue 驱动的静态站点生成器”,底层是 Vite,所以热更新快得离谱,改完 .md 秒刷新,连 Ctrl+R 都懒得按。
但很快发现:默认主题看着干净,但公司 logo 放哪?搜索框怎么关?深色模式能不能强制开?文档里写的配置项 scattered 在不同地方,查一遍文档要翻 7 个 tab。下面这些,是我踩完坑后总结出的**最常用、最实在的配置方式**,亲测有效,直接复制粘贴就能用。
核心配置就三件事:主题、侧边栏、头部导航
项目根目录下 vite.config.ts 只管构建层,真正控制网站结构的是 .vuepress/config.ts(注意:不是 config.js,VuePress 2 全面 TS 化)。别被名字骗了,它其实是个导出对象的模块:
import { defineUserConfig } from 'vuepress/cli'
import { defaultTheme } from 'vuepress/theme-default'
export default defineUserConfig({
title: '前端摸鱼指南',
description: '我们组的开发规范 & 常见问题速查',
head: [
['link', { rel: 'icon', href: '/logo.svg' }],
['meta', { name: 'theme-color', content: '#42b883' }]
],
theme: defaultTheme({
logo: '/logo.svg',
repo: 'https://github.com/our-team/docs',
docsDir: 'docs',
// 搜索关闭(因为内部文档不需要)
search: false,
// 深色模式默认开启(用户偏好不影响)
darkMode: true,
sidebar: [
{
text: '入门',
items: [
{ text: '环境搭建', link: '/guide/setup' },
{ text: '提交规范', link: '/guide/commit' }
]
},
{
text: '实战',
items: [
{ text: 'Vue 组件封装', link: '/practice/vue' },
{ text: 'Webpack 优化', link: '/practice/webpack' }
]
}
],
navbar: [
{ text: '首页', link: '/' },
{ text: 'API 手册', link: '/api/' },
{ text: 'GitHub', link: 'https://github.com/our-team/docs' }
]
})
})
这里注意下,我踩过好几次坑:sidebar 必须是数组,不能是对象;navbar 里的外部链接必须带协议(https://),否则会被当成相对路径,跳转成 /https://xxx。另外,logo 路径是相对于 public 目录的,不是 .vuepress/public,而是根目录下的 public/logo.svg —— 这个我折腾了 20 分钟才意识到。
自定义 CSS?别动主题源码,用 override.css
想改默认主题的按钮颜色、字体大小、代码块背景?千万别去 node_modules 里改 theme-default 的源码(虽然能行,但下次 pnpm install 就没了)。VuePress 提供了标准姿势:.vuepress/styles/override.css。这个文件会被自动注入到所有页面顶部,优先级高于主题默认样式。
比如我们想把所有 <pre> 的背景改成浅灰,加一行就行:
/* .vuepress/styles/override.css */
:root {
--vp-c-bg: #f8f9fa;
}
code {
background-color: #e9ecef;
}
注意:这里用的是 CSS 自定义属性(CSS Variables),VuePress 默认主题大量使用了 --vp-* 前缀的变量,改它们比写一堆 !important 省事多了。官方文档里有完整变量列表,但我建议直接打开浏览器 DevTools,搜 :root 看当前生效的值,更靠谱。
动态侧边栏:按目录自动生成,省得手动维护
文档一多,手动写 sidebar 就成了体力活。VuePress 支持用 sidebar: 'auto',但它只对当前页的 h2/h3 标题生效,没法跨页面聚合。我的解法是写个简单的脚本,在 .vuepress/config.ts 里动态读取 docs/ 目录结构:
import { readdirSync, statSync } from 'fs'
import { resolve } from 'path'
function generateSidebar(dir: string): any[] {
const entries = readdirSync(dir)
return entries
.filter(item => item !== 'README.md' && !item.startsWith('_'))
.map(item => {
const fullPath = resolve(dir, item)
const stats = statSync(fullPath)
if (stats.isDirectory()) {
return {
text: item.replace(/-/g, ' '),
collapsible: true,
items: generateSidebar(fullPath).map(i => ({
...i,
link: /docs/${item}/${i.link || ''}.replace(//+/g, '/')
}))
}
} else if (item.endsWith('.md')) {
return {
text: item.replace(/.md$/, '').replace(/-/g, ' '),
link: /docs/${item}
}
}
})
.filter(Boolean)
}
// 然后在 theme 配置里用:
// sidebar: generateSidebar(resolve(__dirname, '../../docs'))
这段代码不是必须的,但如果你文档目录层级清晰(比如 docs/vue/、docs/css/),它能帮你省掉 80% 的 sidebar 维护时间。缺点是:构建时会多一次 fs 读取,但本地开发根本感觉不到。
踩坑提醒:这三点一定注意
- Markdown 中的 HTML 标签默认不解析:VuePress 2 默认用
markdown-it,它会把<div>xxx</div>当纯文本渲染。想用原生 HTML?在.vuepress/config.ts里加markdown: { html: true },但注意 XSS 风险(内部文档无所谓)。 - 图片路径别写错:md 文件里的
是相对当前 md 文件路径的;而是错的,public 下的资源要写成(前面带斜杠,表示根路径)。 - 部署到子路径要配 base:如果部署到
https://jztheme.com/docs/,必须在 config 里加base: '/docs/',否则所有静态资源路径都会 404。这个我上线前 10 分钟才发现,差点重传整个 dist。
这个场景最好用:把 VuePress 当 API 文档生成器
我们有个内部 REST API,Swagger UI 太重,又不想自己写页面。方案是:用 Swagger 导出 OpenAPI JSON,再用一个轻量脚本(Python 或 Node)把它转成一组 markdown 文件,扔进 docs/api/,VuePress 自动渲染成可读文档。关键点在于:每个接口一个 .md,用 ---<frontmatter>--- 控制标题和侧边栏分组,再配合 override.css 加点高亮样式,效果不输专业工具。
比如 docs/api/users.md 开头这样写:
---
title: 用户相关接口
sidebar: auto
---
### GET /api/users
获取用户列表。
#### 请求参数
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| page | number | 否 | 页码,默认 1 |
#### 返回示例
json
{ “data”: [], “total”: 100 }
VuePress 对 frontmatter 和代码块的处理非常稳,JSON 自动带语法高亮,表格渲染也没毛病——它本来就是为技术文档设计的,别总想着“它是不是太简单了”,很多时候,简单才是生产力。
以上是我踩坑后的总结,希望对你有帮助
VuePress 不是万能的,比如做复杂交互页面(需要大量 JS 逻辑)它就不如直接写 Vue App;但它在“快速产出结构清晰、可搜索、可部署、带版本历史的技术文档”这件事上,依然是我目前用过最顺手的工具。没有花哨功能,但每一步都踩在开发者痛点上。
这个技巧的拓展用法还有很多,后续会继续分享这类博客:比如如何用 VuePress + GitHub Actions 实现 PR 提交自动预览、如何接入 Algolia 搜索、怎么把组件 demo 嵌入文档页……
如果你也有更优的实现方式,或者被某个 bug 卡住,欢迎评论区交流。毕竟,谁还没为一个斜杠多写半小时呢。

暂无评论