用VuePress搭建前端面试知识库:从零构建可检索的Markdown复习手册

用VuePress搭建前端面试知识库:从零构建可检索的Markdown复习手册 说个挺实在的体验准备面试那阵子我手里的 Markdown 笔记散落在好几个文件夹里今天记一道 JS 闭包明天写一段 Vue 响应式原理时间一长连自己存过啥都忘了。后来我把整套内容整合进一个 VuePress 站点用下来最大的感受是它把我的“八股文”笔记变成了一本能检索、能导航、能自动部署成网站的复习手册。这篇东西就是记录我当时怎么一步步从零搭出来的从目录设计、侧边栏配置到部署上线和搜索优化全部走一遍。适合正在准备笔试面试、手里攒了不少零散笔记、又不想用现成博客框架迁数据的人。1. 为什么我把“面试八股文”做成静态站点而不是在线问答库1.1 面试知识积累的真实痛点面试复习这件事痛点不只是“不会”更多是“学过就忘”和“找起来费劲”。我试过各类云端笔记也见过不少人用 Notion、语雀建题库最后发现最大的问题不是记录能力而是组织方式。笔记一旦多起来层级深、散落乱复习时根本没法做到“按模块刷题”“按难度回顾”更别说形成一个稳定的、能对外展示的知识库。我当时给自己定了一个目标所有面试相关的内容必须在一个地方沉淀而且要有清晰的模块划分比如“JavaScript 基础”“浏览器原理”“前端工程化”“手写题合集”等。还有一个额外需求不管是电脑还是手机打开浏览器就能看不用先装软件不用去解压 zip。这就天然倾向于静态站点方案——把 Markdown 文件变成网页部署一次之后改内容只要重新生成即可。1.2 和 GitBook、Docsify、Hexo 横向对比在选型的时候我心里有几个候选GitBook、Docsify、Hexo以及最后选择的 VuePress。每个方案都有自己的适用场景但放到“面试手册”这个具体需求里经过实测比较差别其实非常大。下面是我当时整理的真实感受不是简单的官网特性复述而是上手过一轮后的结论。方案上手成本侧边栏 / 多级导航搜索整合内容形态我的评价GitBook中低比较方便有内置搜索Markdown商业化程度高但本地化部署麻烦新版收费门槛明显Docsify低可配置需要另外做Markdown运行时渲染SEO 差一点内容大时首屏不算快Hexo中偏博客插件生态强大Markdown/MDX擅长写博客但不擅长“文档式”知识导航VuePress中默认主题非常完善内置 插件Markdown Vue文档站体验贴合我这种“手册”需求2.x 后性能也好了很多我自己的结论是Hexo 那套更偏“流水账式博客”按时间线组织对知识分类不友好Docsify 虽然启动快但动态渲染的页面在浏览器里加载全部内容页数多了以后首屏和检索都受拖累GitBook 对新用户不直观、自托管有额外坑。VuePress 最大的优势在于它把“导航、侧边栏、搜索、打包部署”这些做知识库最需要的东西都做成了默认能力而且支持在 Markdown 里写 Vue 组件。这意味着我可以做出很多个性化的小工具而不只是纯静态页面。1.3 内容管理和自动化的边界这里有必要跟没接触过的人说清楚VuePress 本身不负责“管理内容数据库”它本质上是把 Markdown 文件编译成 HTML 的静态站点生成器。你在本地有一个docs文件夹里面全是.md文件写完以后执行vuepress build docs它会生成一堆 HTML、CSS、JS丢到任意静态托管平台就能跑。内容管理靠文件系统你只需要维护好文件夹和命名规范剩下的交给约定和组织。说实话这种“文件即内容”的模式对单个开发者来说体验比数据库后台更好用。因为你可以直接用编辑器批量移动、重命名、搜索替换Markdown 本身就是一种长期可读的格式未来就算换技术栈内容也不会被锁定在某家平台里。而且支持 Git 管理每一次修改都有记录复习稿迭代了多少版、哪些题目更新过一目了然。2. 初始化项目与目录设计2.1 环境准备与脚手架命令2022 年那会儿 VuePress 2.x 已经比较成熟我也果断从 1.x 迁到了 2.x。如果你想复现这个过程建议先确认 Node 版本最好在 16 以上因为 VuePress 2.x 对 Node 版本有要求太老的环境跑vuepress dev很容易碰到模块兼容报错。准备好环境后创建项目只需要几步mkdir interview-manual cd interview-manual npm init -y npm install -D vuepressnext vuepress2.0.0-beta.53装完后在package.json里加上常用脚本{ scripts: { docs:dev: vuepress dev docs, docs:build: vuepress build docs } }接着建一个docs目录并在docs下创建README.md里面随便写点内容。然后执行npm run docs:dev浏览器打开http://localhost:8080看到页面就算初始化成功。这里有个小细节VuePress 默认把项目约定为“源码目录”你项目里的docs文件夹就是所有文档内容的根目录最好不要把别的工程文件塞进docs否则构建时会多出不必要的文件扫描。2.2 目录结构到底怎么设计才合理一个面试手册如果不提前划分好目录后期整理成本会越来越高。我的建议是顶层目录按照“知识域”划分而不是按照来源或时间划分。比如我最初的结构是docs/ ├── README.md ├── .vuepress/ │ ├── config.js │ └── public/ ├── javascript/ │ ├── README.md │ ├── 01-closure.md │ ├── 02-this.md │ └── 03-promise.md ├── css/ │ ├── README.md │ ├── 01-box-model.md │ └── 02-flex-layout.md ├── vue/ │ ├── README.md │ ├── 01-reactive.md │ └── 02-lifecycle.md ├── network/ │ ├── README.md │ ├── 01-tcp-handshake.md │ └── 02-http-cache.md └── algorithms/ ├── README.md └── 01-array.md这里的命名规范是“数字序号 主题名”。为什么这么设计因为 VuePress 默认侧边栏如果没有单独配置会按照文件名的字典序排序我如果用01-closure.md这样的前缀就可以人为控制每篇文档的展示顺序。类似的每个知识域下的README.md会作为该目录的入口页打开javascript/时先看到的是这个入口的简介而不是一片空白。另外我强烈建议在docs根目录放一个README.md里面写清楚这份手册的使用方式比如“每天按模块刷一遍标绿的表示已掌握”。这样部署之后首页就是一个引导页自己访问时心理负担小别人看到也不至于一头雾水。2.3 文档目录与侧边栏的映射关系很多人在 VuePress 里踩的第一个坑就是“为什么我建立了文件夹侧边栏没有自动生成”VuePress 1.x 默认会做一些自动侧边栏处理但 2.x 里如果想稳定控制侧边栏更推荐的还是显式配置。表面上看好像多了一步手写配置其实对长期维护是好事目录层级一旦乱起来自动生成的侧边栏往往会给你惊喜显式配置则能保证每次渲染结果都可预期。我的经验是先定目录、再写侧边栏配置。具体来说.vuepress/config.js里通过themeConfig.sidebar来设置侧边栏。针对上面那个目录我当时的侧边栏配置大致长这样module.exports { lang: zh-CN, title: 面试手册, description: 前端面试知识点与手写题汇总, themeConfig: { logo: /logo.png, nav: [ { text: 首页, link: / }, { text: JavaScript, link: /javascript/ }, { text: Vue, link: /vue/ }, ], sidebar: { /javascript/: [ { text: JavaScript 基础, collapsible: true, children: [ /javascript/01-closure.md, /javascript/02-this.md, /javascript/03-promise.md, ], }, ], /vue/: [ { text: Vue 原理, collapsible: true, children: [ /vue/01-reactive.md, /vue/02-lifecycle.md, ], }, ], }, }, };这里我用了对象形式的sidebar按路径分区块配置这比全局数组形式的侧边栏灵活得多。要注意路径必须以/开头并且指向的是docs目录下的相对路径不要写成从项目根目录出发的完整路径。此外路径结尾的小写目录名要和实际文件夹保持一致。部署到 Linux 服务器时大小写敏感的问题会直接导致页面 404这是我实测踩过的坑。3. 核心配置与内容写作技巧3.1 config.js 里那些值得多看一眼的配置项除了导航和侧边栏config.js里还有几个配置项对面试手册场景特别有用我逐一说明。首先是lang我会设置为zh-CN这会影响站点语言和浏览器、搜索引擎对页面语言的理解对中文内容 SEO 也有辅助作用。其次是head可以往 HTML 的head里注入自定义标签比如引入字体、添加 meta 描述。我当时顺手加了主题颜色和关键词 meta生成后的页面在搜索分享时会更漂亮。module.exports { head: [ [meta, { name: theme-color, content: #3eaf7c }], [meta, { name: keywords, content: 前端面试, VuePress, 八股文, 面试题 }], ], };还有一个容易被忽略的是markdown配置。VuePress 2.x 默认支持代码高亮但如果你需要行号、特定语言的代码块渲染可以在markdown选项里做更细的调整。比如把code的行号显示打开对“手写题”尤其有用——读者能看到每一行代码的顺序和缩进而不是一大片看不清的字符串。module.exports { markdown: { lineNumbers: true, }, };3.2 侧边栏的三种玩法手写、半自动、全自动侧边栏这块我花了不少时间研究因为我既想要控制力又不想每次加文章都改配置。最终我总结出三种玩法按需求程度不同可以选。第一种是纯手写。就是上面给出的方式路径写死在配置里。好处是结构完全可控坏处是新增一篇文章时必须同步改配置否则不会出现在侧边栏里。第二种是半自动。也就是只配置侧边栏分组但每个分组下的文件列表通过读取目录文件生成或者在README.md里用相对链接的方式自己维护一个“目录页”。这样既能看到页面又不会完全依赖 VuePress 的默认行为。第三种是全自动。可以写一个 Node 脚本构建前扫描目录自动生成侧边栏配置对象再注入到config.js或者单独导出的sidebar.js。这种方式适合内容特别多、更新特别频繁的手册。我当时因为内容已经开始膨胀就写了一个很粗的脚本通过fs读取目录结构把二级目录下的*.md文件转为侧边栏 children。优点是省事缺点是一旦目录文件命名不规范脚本生成的侧边栏会乱掉。如果你只是个人用我建议从手写开始等真的感觉每次加文件太繁琐了再切换到脚本生成。不要一上手就自动化否则排查渲染问题时你会多一层的变量。3.3 用 Markdown 增强语法把答题模板写活VuePress 的 Markdown 不只是普通 Markdown。它内置了container自定义容器可以写提示框、警告框、危险提示等。这在面试手册里非常实用每个问题的标准答案和面试官追问部分我可以用不同容器区分开一眼就能看出哪些是基础结论哪些是扩展考点。举个例子我在 JS 闭包那篇文档里是这样写的::: tip 结论一句话 闭包是指函数能够访问其词法作用域之外的变量。在 JavaScript 中每次创建函数时都会在函数内部保存对词法环境的引用这就形成了闭包。 ::: ::: warning 常见追问 如果闭包引用的变量在外部被修改闭包内部看到的是最新值还是旧值答最新值因为闭包保存的是变量对象引用而不是当时的快照。 ::: ::: details 手写例子 function createCounter() { let count 0; return function () { count 1; return count; }; } const counter createCounter(); console.log(counter()); // 1 :::这个写法最大的好处是复习时我不需要读完整段长篇大论只扫一眼提示框里的结论就能快速回忆起核心点。需要深入时再点开 details 折叠块看代码。比纸质笔记好用得多也比静态图片分享方便得多。如果你愿意甚至可以约定一套颜色规范比如“tip 表示记忆口诀、warning 表示易错点、danger 表示高频面试坑”把整本手册做成一个可扫读的复习卡。3.4 在八股文页面里嵌入 Vue 组件做打卡这是 VuePress 相对其他静态站生成器最让我惊喜的一点。Markdown 文件里可以直接写 Vue 组件。意味着我不只能写文档还能把“复习进度打卡”“随机抽题”“答案展开折叠”之类的小工具做成组件插进文档里用。我当时做了一个简单的“每日打卡”组件放在首页。代码不复杂随便贴一下核心思路template div p今天已复习 {{ checkedCount }} / {{ total }} 个模块/p button clickcheckIn打卡/button /div /template script setup import { ref } from vue const checkedCount ref(0) const total ref(12) function checkIn() { checkedCount.value 1 } /script这个组件编译后会打包进页面加载方式比单纯静态页面多了一点交互。当然这里有个限制由于是静态站点没有后端数据没法持久化保存。我的做法是把打卡结果通过localStorage存在浏览器本地这样在同一台电脑上复习进度不会丢。如果你需要跨设备同步那就是另一个话题了得自己接存储服务才行。在面试复习这个场景里我用这个方式实现了“随机抽题按钮”——每次刷新从数组里随机取一道题显示。这比固定顺序刷题更能检测真实掌握程度因为面试时你并不知道下一个问题是什么。4. 搜索、插件与阅读体验优化4.1 本地搜索和第三方搜索怎么选面试手册内容多了以后光靠侧边栏点来点去是不够的。想象一下你在复习“协商缓存”如果每道题都要先从侧边栏找到 HTTP 缓存那篇再往下翻到对应标题效率很低。这时候就要靠全文搜索。VuePress 2.x 默认是带本地搜索能力的但需要做一些配置。如果你用的是默认主题可以安装vuepress/plugin-search插件。这个插件基于 minisearch 实现对个人站点来说非常轻量支持全文搜索不需要后端服务。配置方式也很简单npm install -D vuepress/plugin-searchnext然后在 config 里引入const { searchPlugin } require(vuepress/plugin-search); module.exports { plugins: [ searchPlugin({ locales: { /: { placeholder: 搜索面试题, }, }, maxSuggestions: 10, hotKeys: [s, /], }), ], };这里hotKeys可以设置快捷键按s或/就能唤起搜索框复习时手不离键盘效率提升明显。如果你的内容量很大、且对搜索精确度有更高要求可以考虑付费接入 Algolia DocSearch但那个需要网站有公开域名并且要去申请。对个人手册来说本地搜索完全够用。4.2 我常用的几个插件组合除了搜索插件还有几个插件我用了之后觉得不错这里列出来供你参考。第一个是vuepress/plugin-pwa可以把站点变成 PWA支持离线访问和更加接近 App 的体验。对复习类工具来说离线能力简直是加分项地铁里没信号也能看题。npm install -D vuepress/plugin-pwanext用的时候注意PWA 插件要求站点是 HTTPS 部署并且需要你提供一个 512x512 的图标。配置时如果没有图标构建不会失败但实际运行时安装提示会消失。第二个是vuepress/plugin-git可以统计每篇文档的最后更新时间和贡献者信息。对单人手册来说“最后更新时间”字段非常有用能提醒我这篇笔记是不是太久没更新了。老旧的答案在技术迭代后可能已经过时没这个字段我根本想不起来去核对。第三个是vuepress/plugin-seo和vuepress/plugin-sitemap这俩是社区插件用来生成 SEO 元数据和 sitemap 文件。如果你的手册打算公开分享、想让搜索引擎收录可以考虑加上。不过面试手册这种内容搜索引擎收录的价值优先级不高我当时的排序是搜索、PWA、Git 信息最后才是 SEO。4.3 阅读体验调整深浅色、字体、高亮阅读体验这件事初期会觉得无所谓但当你连续刷两个小时题眼睛开始有感觉的时候才知道深浅色切换和合理字体有多重要。VuePress 默认主题自带主题切换按钮但我当时做了一些细调比如把正文的max-width调到一个舒服的宽度避免文字过长影响阅读又比如调整了代码高亮主题让代码块和正文的对比更清晰。如果你不想自己写样式可以在.vuepress/styles/index.scss里覆盖默认变量。常用的变量包括主色、链接颜色、代码背景色等。例如$accentColor: #2c6fbb; $textColor: #2c3e50; $codeBgColor: #282c34;这种方式的好处是不用去动源码改完构建后全局生效。需要注意的是VuePress 2.x 的默认主题样式变量名可能跟 1.x 有区别直接照搬网上旧文章容易失效建议先在项目里查一下实际的变量定义文件再改。5. 部署上线从本地到公网5.1 GitHub Pages 部署流程手册本地能用只是第一步真正让它变成“随时随地都能访问”的复习工具还得部署到公网。我的首选是 GitHub Pages因为它对静态站点免费、支持自定义域名而且和 Git 配合很顺滑。但这里有个容易踩的坑如果你的项目仓库名不是user.github.io这个格式而是随便取的名字比如interview-manual那么构建产物的资源路径需要特殊处理。VuePress 默认生成的资源引用路径是以/开头的部署到子路径下会全部 404。解决办法是给 config 设置basemodule.exports { base: /interview-manual/, };如果部署在根域名下base就是默认的/。如果你不确定自己部署在什么路径可以先统一设置成仓库名后面再按实际情况调整。我的经验是不要等部署完发现 404 才处理在一开始搭项目时就在config.js里把base写好。5.2 服务器部署与 Nginx 配置如果你有自己的云服务器也可以用 Nginx 托管静态文件。这种方式的好处是不受 GitHub 访问限制的影响国内访问速度也好一些。部署过程听起来简单把docs/.vuepress/dist目录下的文件丢到服务器某个目录再配置 Nginx 指向这个目录就完成了。但实际有几个细节值得注意。我在自己的服务器上配置大概是这样的server { listen 80; server_name your-domain.com; root /var/www/interview-manual; index index.html; location / { try_files $uri $uri/ /index.html; } }这里有个重要的点VuePress 生成的是纯静态页面但 SPA 路由部分在刷新时会导致 Nginx 去找实际不存在的路径。加try_files可以回退到index.html保证路由不出现 404。如果你只在 GitHub Pages 部署那不太会遇到这个问题因为 GitHub Pages 对静态文件的处理方式不完全一样。但自己服务器上一定要记得加。另外我强烈建议部署时给站点加 HTTPS。现在申请证书已经非常简单免费的 Let’s Encrypt 就够用。没有 HTTPS 的话PWA 插件和浏览器的一些新 API 都会失效而且对用户也不友好。5.3 用 GitHub Actions 自动发布手动部署一两次还好频繁更新笔记、每次都重新 build 上传很快就会烦。所以我后来加了 GitHub Actions只要git push自动完成构建和发布。这样我在本地只做一件事写完 Markdown提交推到远程剩下的不用管。一个简单的 workflow 大致长这样name: Deploy on: push: branches: [main] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkoutv3 - name: Setup Node uses: actions/setup-nodev3 with: node-version: 16 - name: Install dependencies run: npm install - name: Build run: npm run docs:build - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pagesv3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs/.vuepress/dist第一次配置的时候很多人会卡在gh-pages分支的创建或 token 权限上。其实 GitHub Actions 默认提供了GITHUB_TOKEN只要在仓库 Settings 里允许 workflow 写入权限就可以直接部署。不需要额外生成 token。这里注意publish_dir一定要指向正确的产物目录如果路径写错了部署出来的页面会是旧版或者空白。6. 常见问题与踩坑记录6.1 典型问题排查速查表我自己在搭 VuePress 面试手册的过程中被几个问题卡过不少时间这里整理成一张速查表希望你能跳过这些坑。现象可能原因解决办法部署后页面 404base配置不对根据仓库名或子路径设置正确的base侧边栏不显示没有配置sidebar在themeConfig里显式配置侧边栏代码块没有高亮语言标识不对或缺少插件检查代码块的 fence 语言名如js、bash本地开发页面错乱Node 版本过低升级到 Node 16删除node_modules重装修改 config 后没生效dev server 缓存先停掉npm run docs:dev重新启动搜索结果不准搜索插件范围配置不当检查searchPlugin的 locales 与maxSuggestions图片资源 404资源路径写错图片放到.vuepress/public路径不要带中文这张表未必覆盖所有场景但大多数刚接触 VuePress 的人遇到的问题都集中在这几类。遇到问题时我习惯先去检查config.js里有没有语法错误再看浏览器控制台有没有资源加载失败这样能快速定位到底是配置问题还是文件路径问题。6.2 几个容易被忽视的细节如果要说我最想提醒的细节第一个是文件路径的大小写。在本地 macOS 或 Windows 上文件名大小写不敏感但部署到 Linux 服务器后大小写不匹配就会 404。我吃过这个亏最终解决方式是每次写完文档后用脚本批量检查文件名和内部引用是否一致。VuePress 的链接解析比较严格如果内部链接大小写不一致本地可能没问题线上就完了。第二个细节是不要过于依赖自动侧边栏。VuePress 2.x 的默认主题在“自动侧边栏”上其实没有做到很多人期待的那种全自动如果你发现侧边栏没有你刚建的文档正常现象不要怀疑自己装错了包。老老实实写配置或是用脚本生成配置反而更快。第三个细节是关于图片路径。如果你是像我一样把图片放在.vuepress/public下那么引用图片时路径要写成/img/xxx.png而不是相对路径。相对路径在某个二级页面里可能指向了错误的位置。我当时因为这个反复确认了好几次最终统一改成绝对路径再没出过问题。第四个细节是代码块里嵌套的内容。面试手册里经常要展示“源码 输出结果”如果你在 Markdown 代码块里继续写 Markdown 语法会渲染错乱。我后来养成了一个习惯所有示例代码一律只写纯代码遇到需要同时展示解释的就把解释放到提示容器里。这样构建时不会出现疯狂的嵌套报错。6.3 内容维护的长线建议最后聊一点内容上的经验。一开始建手册时我总想写得“全面”每个知识点都想覆盖得滴水不漏。后来发现这种全量思维导致更新频率很低因为每篇文档都写得特别长。后来我改了策略每篇文档只要求能回答“这道题在面试里怎么答”这一个问题答完就收尾。以这样的思路推进手册的完成度反而提高得很快。在此基础上我还给自己定了一个“每周修订日”每周抽 30 分钟把临时的碎片笔记整理进手册。这个习惯一直坚持下来手册才从一个启动项目变成真正每天都会打开的工具。工具的价值从来不在于装了什么强功能而在于你用它的频率。我在实际使用中最大的体会是VuePress 本身只是一个“渲染 Markdown 的引擎”真正让这本手册好用的是我不断根据复习习惯调整它的结构。比如后来我加了更多折叠块、更多打卡组件甚至在文章页底部嵌入了一个“是否掌握”的选择按钮虽然数据只存在浏览器里但每次复习后的即时反馈让人更容易坚持下来。如果你也准备做一本属于自己的面试手册不要着急一上来就把所有功能都配齐先写内容、再优化结构最后再补工具链。内容到位了工具自然会有用武之地。