用VuePress搭建技术博客的实战经验与常见坑点总结

迁迁 Dev 框架 阅读 1,323
赞 15 收藏
二维码
手机扫码查看
反馈

先看效果,再看代码

上周给团队搭内部文档站,选了 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 都懒得按。

用VuePress搭建技术博客的实战经验与常见坑点总结

但很快发现:默认主题看着干净,但公司 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 || &#039;&#039;}.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 文件里的 ![](./img/foo.png) 是相对当前 md 文件路径的;而 ![](../public/img/foo.png) 是错的,public 下的资源要写成 ![](/img/foo.png)(前面带斜杠,表示根路径)。
  • 部署到子路径要配 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 卡住,欢迎评论区交流。毕竟,谁还没为一个斜杠多写半小时呢。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论