第一次认真想搭一套属于自己的技术文档站,起因特别朴素:笔记写了一堆,随处散落,想找某个接口说明的时候反而要翻好几个地方。后来试过在线文档,协作虽然方便,但排版总是被编辑器牵着走,代码块一贴就变形,版本管理更是完全谈不上。折腾一圈之后,我重新回到 Markdown + 静态站点的老路上,最后固定下来用的就是 VuePress。如果你也正在为"怎么把 Markdown 内容变成一套像样的技术文档"发愁,这篇内容应该能帮你少绕不少弯。我会从选型逻辑开始,把环境、配置、Markdown 增强、构建部署这些环节串起来,手把手走一遍完整流程。
1. 为什么我最终选了 VuePress,而不是其他文档方案
1.1 写技术文档最大的痛点:内容被格式绑架
做过技术写作的人都懂,文档这件事最耗精力的往往不是"写",而是"排"。今天换个表格样式,明天调一下代码块高亮,后天觉得目录层级不对,一天下来真正落在文字上的时间没多少。我自己最崩溃的一次经历,是把一篇长文档从在线编辑器迁移到本地时,所有嵌套列表全部错位,表格里的竖线变成了纯文本。从那以后我给自己定了个规矩:内容层和展示层必须分离,内容只写 Markdown,展示交给模板和主题去处理。这正好是 VuePress 这类静态站点生成器最擅长的事情。
另一个痛点是发布流程。早期我写笔记基本都是自嗨,等真要分享给其他人时,才发现没有一个稳定的链接可以用。静态站点方案把文档变成一堆普通的 HTML 文件,扔到任意一台静态服务器上就能访问,既不需要后端,也不需要数据库。配合持续集成,每次提交完内容,站点会自动更新。这套流程跑通之后,我几乎再也没有被"发布"这件事困扰过。
1.2 主流文档方案快速对比
在确定 VuePress 之前,我也认真对比过几个常见的思路,这里把当时的判断过程分享一下。
| 方案 | 核心特点 | 适合场景 | 我当时的顾虑 |
|---|---|---|---|
| VuePress | 基于 Vue 的静态站点生成器,构建后输出纯静态 HTML | 中小型技术文档、组件库文档、个人博客 | 生态相对稳定,自定义组件需要一点 Vue 基础 |
| VitePress | VuePress 的下一代版本,构建速度更快 | 偏新的项目、对构建速度敏感的场景 | 插件生态和默认主题还在完善中 |
| Docsify | 运行时渲染 Markdown,无需预先构建 | 快速搭建的轻量文档 | 搜索引擎抓取和首屏加载不如静态构建友好 |
| mdBook | Rust 生态,目录结构简单 | 偏爱简洁的开发者 | 扩展能力相对有限,Vue 体系内用不顺 |
| Docusaurus | 基于 React,功能全面 | 大型开源项目的社区文档 | 上手成本和学习曲线都不算低 |
综合来看,VuePress 对我的吸引力在于:它不要求你先把整个前端工程体系搞懂,却保留了"文档站可以带有交互能力"的可能性。Markdown 写不下去的时候,可以用 Vue 组件补上复杂交互,比如 API 表格、组件 Demo、代码运行示例。这种"下限很低、上限很高"的弹性,在同类工具里是少见的。
1.3 VuePress 解决的核心问题
VuePress 做的事情可以一句话概括:把 Markdown 文件当作一等公民,在构建阶段把它们编译成 Vue 单文件组件对应的静态页面。你在项目里看到的 source 文件是 Markdown,但实际跑起来时,每个页面背后都是一个 Vue 应用。这个设计带来几个非常实在的好处:
- 普通团队成员的参与门槛低,只要会写 Markdown 就能贡献文档,不用理解 Vue 细节。
- 需要高级能力时,又能直接在 Markdown 里引入 Vue 组件,实现自定义区块、交互式示例等。
- 构建产物是完全静态的 HTML、CSS、JS,部署环境极其宽松,也方便接入各种自动化流程。
从本质上看,VuePress 更像是一个"让文档具备工程化能力"的中间件:内容留在 Markdown,工程能力藏在底层。理解了这层关系,后面所有配置都会变得很顺。
2. 环境准备与项目初始化:先把架子搭起来
2.1 本机前置条件:Node 环境怎么选
VuePress 归根结底是一个 Node.js 应用,所以第一步是确认电脑上有可用的 Node 环境。我用的是 Node 长期支持版本,目前比较稳妥的是 16 及以上版本。
node -v npm -v如果你机器上有多个版本,建议在项目目录里单独记录 Node 版本,避免过半年再回来看项目时,因为版本差异跑不起来。我的习惯是在项目根目录放一个.nvmrc文件,里面写上当前使用的版本号,这样换机器或者新同事接手时,一条命令就能切换环境。
npm 的镜像配置看个人网络情况,不需要迷信某个源,能正常拉包就行。这里有一个经验:遇到依赖安装慢或者超时,先查镜像源配置,再考虑升级 npm 版本,顺序反了会平白增加很多无效等待。
2.2 创建项目并进入交互式初始化
在空目录下打开终端,执行初始化命令,VuePress 的官方脚手架会引导你完成基础配置。
npm create vuepress@latest运行之后,按照提示选择项目所在的目录名称、包管理器,通常用 npm,然后等待依赖安装完成。这里有个容易忽略的点:脚手架会问你文档目录放在哪里,默认一般是一个docs文件夹,建议保留这个约定。因为 VuePress 的很多默认配置和官方文档路径都是围绕docs目录设计的,后续参考资料时会省很多解释成本。
依赖安装完之后,项目结构大致是这样的:
my-docs/ ├─ docs/ │ ├─ .vuepress/ │ │ ├─ config.ts │ │ └─ public/ │ ├─ guide/ │ │ ├─ install.md │ │ └─ config.md │ └─ index.md ├─ node_modules/ └─ package.jsondocs目录是内容源码区,docs/.vuepress目录是配置和主题相关的专属区域,index.md默认会作为站点首页。初学者最容易犯的错是往.vuepress里乱放普通文档页,结果页面路径变得又长又乱。记住一个原则:.vuepress里只放配置、主题、全局组件和静态资源,其他 Markdown 文件一律放在docs下的普通子目录里。
2.3 启动本地开发服务的验证方法
依赖装好后,执行下面的命令启动开发服务器,程序默认会在http://localhost:8080提供预览页面。
npm run docs:dev第一次跑起来,你会看到一个带左侧导航和顶部导航的默认站点,这就说明脚手架配置正确。这里建议先花两分钟点开几个内置页面,把默认主题的展示效果大致过一遍,心里有个底,再去动配置。很多人一上来急着改样式,结果连默认站点结构都没看全,后面越改越乱。
如果发现启动报错,优先检查两个方向:一是 Node 版本是否满足 VuePress 的要求,二是node_modules是否安装完整。遇到EADDRINUSE端口冲突时,在配置文件中改一下port字段即可。
3. 核心配置:导航栏、侧边栏和首页定制
3.1 配置文件的角色划分
VuePress 的全局配置集中在docs/.vuepress/config.ts或config.js里。打开这个文件,最外层一般会有title、description、base、themeConfig这几个字段。
module.exports = { lang: 'zh-CN', title: '我的技术文档', description: '一套基于 VuePress 的团队文档站点', base: '/', themeConfig: { logo: '/images/logo.png', navbar: [], sidebar: [] } }title和description一方面会显示在浏览器标签页上,另一方面会被搜索引擎抓取,是站点的"门面信息"。base字段则关系到部署之后站点的访问路径,如果域名根路径访问就填/,如果要部署在一个子目录下,就要改成/你的目录名/,这个我后面单独讲。
3.2 导航栏配置的常见套路
主题配置里的navbar字段负责顶部导航。最常用的写法是直接给一个字符串路径,也可以加上text和link指定显示文字和目标页面。
themeConfig: { navbar: [ { text: '首页', link: '/' }, { text: '指南', link: '/guide/' }, { text: 'FAQ', link: '/faq/' } ] }导航项不宜多,顶多五六个,否则顶部空间会显得很挤。如果有二级分类需求,可以把多个相关页面塞进一个下拉菜单里,用children数组表示。
3.3 侧边栏:手工配置还是自动生成
侧边栏是技术文档体验的关键。VuePress 的默认主题支持两种用法,一是按目录自动生成,二是在配置里手工指定。我自己对文档的分类和排序要求比较高,所以更偏向手工配置。
sidebar: { '/guide/': [ { text: '基础入门', children: ['/guide/install.md', '/guide/config.md'] }, { text: '进阶实践', children: ['/guide/deploy.md', '/guide/faq.md'] } ] }这种写法把侧边栏的分组语义直接写死在配置里,看起来更直观。代价是每新增一篇文档,要记得同步维护sidebar。如果要频繁添加页面,可以用目录自动生成的方式,代价是排序和组织方式不那么灵活。两种方式没有绝对好坏,我建议先手工配置几天,感受一下维护成本,再决定要不要自动化。
3.4 首页的美化与内容布局
docs/index.md是首页源文件,它的 front matter 字段决定了首页展示什么内容。
--- home: true title: 首页 heroText: 我的技术文档 tagline: 把知识沉淀成可持续维护的站点 actions: - text: 快速开始 link: /guide/ features: - title: 简洁 details: 基于 Markdown 写作,专注于内容本身 - title: 可维护 details: 构建产物是静态文件,部署升级都很方便 - title: 可扩展 details: 需要时可以用 Vue 组件增强页面交互 ---hero 区域适合放项目的一句话定位,features 区域适合放三个核心卖点。整套首页的排版由默认主题负责,不建议过度定制,否则很容易陷入样式细节里,耽误内容建设。等到内容足够丰富了,再考虑把首页替换成完全自定义的 Vue 组件也不迟。
4. Markdown 扩展:让技术文档真正好读起来
4.1 提示、警告和危险容器
技术文档有一个特殊需求:区分"普通说明"和"重点提醒"。VuePress 的 Markdown 扩展提供了现成的容器语法,写作体验和 final 输出效果都不错。
::: tip 这里是一句温馨提示,适合放使用建议。 ::: ::: warning 这里是一句警告,适合提示容易踩的坑。 ::: ::: danger 这里强调高危操作,适合提醒不可逆的变更。 :::三个容器的视觉样式在默认主题里已经定义好了,不需要额外配 CSS。我自己的使用习惯是:tip用在新手友好提示,warning用在可能影响现有功能的情况,danger只留给回滚困难的操作。
4.2 代码块分组和行号
技术文档离不开代码示例。VuePress 内置了代码高亮,并通过代码块容器支持同时展示多个 Tab 版本,对中文文档尤其好用,因为经常要贴"npm、Yarn、pnpm"三种安装命令。
::: code-tabs @tab npm npm install @tab yarn yarn add @tab pnpm pnpm install :::代码块本身可以开启行号,也可以批量高亮某几行。示例代码尽量控制在一个屏幕内,过长的大段代码放在可折叠区域里,避免读者一进来就被密集代码淹没。这是我写了半年文档之后总结出来的阅读体验规律:先让人看懂结构,再给人全量代码。
4.3 目录、锚点跳转与图片管理
在长文档开头放一个[[TOC]],页面会自动生成当前页面的目录树,方便读者快速定位到对应小节。锚点跳转则是 Markdown 自带的能力,结合[跳转到 3.2 节](./第3章.html#配置)XXXX这样的相对链接,可以在文档之间灵活跳转。
图片管理方面,建议把静态图片统一放在docs/.vuepress/public下,页面里引用时以/images/xxx.png相对根路径访问。这样做的好处是,图片不跟随正文文件分散在多个目录,后续做 CDN 分发或清理素材时很方便。需要注意图片命名尽量用英文字母和连字符,别用中文名和空格,否则在部分环境会出问题。
4.4 复杂页面用 Vue 组件兜底
Markdown 再强大,也总会有表达力不够的时候。比如要做一个交互式 API 参数表,或者一个带运行按钮的在线示例,纯 Markdown 就很难实现。VuePress 允许你在 Markdown 中直接使用 Vue 组件,操作步骤是:在docs/.vuepress/components目录下新建一个.vue文件,然后在任意 Markdown 页面里以标签形式引入。
我写过的最实用的一个自定义组件,是一个版本切换器:读者可以选择查看左边 "v1 版本"还是"v2 版本"的接口说明,同一份页面承载两套文档,阅读体验比硬塞两个章节好很多。这类组件本质上就是普通的 Vue 单文件组件,写完注册即可,不熟悉 Vue 的同学可以先从简单的展示型组件开始,比如徽标、标签、状态点之类的。
5. 从本地到线上:构建、部署与路径问题
5.1 构建产物的意义
开发模式下,VuePress 会在内存中渲染页面,方便热更新。但要真正发布到线上,必须执行构建命令。
npm run docs:build构建完成后,产物输出在docs/.vuepress/dist目录。这里的 dist 目录就是一个完整的静态站点,你可以把整个目录直接扔进任意一个静态托管服务。我看过不少人第一次构建后四处找产物文件,这里先说明白:不是public,不是src,就是.vuepress/dist,一个在默认配置下几乎不会暴露在 IDE 文件树里的隐藏目录。
5.2 base 字段:子路径部署的隐形杀手
如果站点最终访问地址是https://example.com/docs/这种子路径形式,那么必须在配置里设置base: '/docs/'。一旦忘了配置或者配置错了,最常见的症状是:首页能打开,但任何二级页面刷新后全变成 404,或者页面里的 CSS、JS 全部加载失败。
这背后的原因不复杂:VuePress 生成资源引用时是按绝对路径写的,根路径部署用/没问题,子路径部署就必须在资源路径前加上子路径前缀。我的建议是,部署方案敲定之前先不配base,等到接入具体的托管服务后,第一时间就用线上地址去验证刷新和资源加载是否正常。
5.3 部署到静态托管的通用流程
如果你的项目用的是代码托管平台,部署 VuePress 站点的核心逻辑非常固定,大概分四步:
- 构建命令设置为
npm run docs:build,产物目录设置为docs/.vuepress/dist。 - 推送 Markdown 源码到仓库,让平台监听分支变化。
- 部署平台自动执行构建,并把产物发布到静态托管服务。
- 域名解析到对应托管服务地址,配置好 HTTPS 证书。
不同平台的操作界面和方法会有差异,但本质都是"推送触发构建、产物对外服务"。考虑到后续要长期维护,强烈建议把部署流程自动化,别每次手动scp上传 dist 目录。自动化之后,文档更新频率可以大幅提升,因为成本低了,人反而愿意多写。
5.4 多环境与多版本并存
如果你的文档涉及多个版本,比如一套旧版、一套新版,可以考虑部署两套文档到不同子路径:旧版部署在/v1/,新版部署在/v2/,再用主站默认跳转到新版。VuePress 配置中的base按站点维度区分,而不是按单个页面区分,所以多版本发布最简单的方式是建立两个独立的构建流程,分别指定不同的base,再把产物部署到不同前缀下。
这个思路比在单站里做大量条件判断要省心得多。版本之间切换的入口放在导航栏或首页显著位置,读者一眼就知道自己正在看的是哪套文档。
6. 维护过程中积累的一些经验和习惯调整
6.1 踩过的几个坑和识别方法
文档站点内容相对简单,但运行环境的问题依然能让人头疼。我踩过比较典型的坑包括:
- 在不同操作系统上切换项目时,文件大小写不一致导致构建报错。Markdown 文件名必须保持一致,特别是在 Mac 和 Windows 之间同步项目时,最好统一使用小写字母和连字符。
- Node 版本升级后,依赖树出现兼容错误。这类问题表现得很奇怪,可能只在执行
docs:build时出现,但docs:dev又正常。先检查当前 Node 版本是否和项目初期一致,再考虑升级依赖。 - 图片路径写错但开发环境却表现正常。开发环境对缺失资源很宽容,构建后的站点会留下大量 404。后来我养成一个习惯:每次构建完成,先跑一遍本地静态服务器预览 dist 目录,而不是直接发布后再去线上检查。
- 侧边栏维护跟不上新增文档。这个问题不属于 Bug,但比 Bug 更容易拖垮文档质量。后来我给自己定了一个规则:新建文档时连 sidebar 配置一起改,不允许只有文件没有目录入口。
6.2 内容组织上的三个建议
技术文档维护到后面,真正决定质量的是内容结构,而不是工具。基于我的使用经验,有几点可以分享。
第一,目录层级控制在三层以内。太深的嵌套会让路由、侧边栏、面包屑全部变复杂,读者也容易迷路。第二,定一个文档命名规范,比如全部使用小写英文、用连字符连接多个单词、同年月日保持一致的命名前缀。第三,维护一个/faq/faq.md页面,把日常遇到的高频问题统一放在里面。有 FAQ 入口的文档站,搜索压力会小很多,因为很多重复性问题可以在一个页面里得到解答。
6.3 关于写作频率和更新节奏
静态站点方案最大的优势是发布成本低,但这个优势需要配合一定频率的更新才能发挥出来。我会把文档更新跟功能开发放在同一个工作流里:做完一个功能,顺手写一页文档;修完一个 Bug,顺手把 FAQ 补一条。积少成多,站点不会出现"几个月没动过"的颓势。
个人体会是,VuePress 真正教会我的不是某个具体配置怎么写,而是"文档也是代码"这个观念。内容用 Markdown 沉淀,结构用 Git 管理,发布用自动化流程完成,整个过程和写代码的体验高度一致。最后再分享一个小技巧:每次改完配置后,认真的npm run docs:build一次,看构建日志里有没有链接警告,有就顺手修掉。别让失效链接在文档里堆积,这个问题越早处理越省力,拖到一股脑爆出来时,排查成本会非常难受。