2022 年,教你用 VuePress 创造属于自己的「面试八股文」手册

1,989 阅读11分钟

我正在参与掘金创作者训练营第4期,点击了解活动详情,一起学习吧!

👈2021 年,你是否曾经幻想着拥有一个属于自己的「知识体系文档」或「面试八股文」手册,却迟迟不知如何下手?

👉2022 年,是该结束这一切臆想了,本文将介绍如何用 VuePress 搭建一个知识文档,跟着我一起实践起来吧!

🚄前言

近几日想将自己的知识体系【技术栈】梳理成文档(文档在手,Offer 我有),方便日后复习所积攒的知识。

但我又不想使用 Halo 再搭建一个同样的博客,那样太乏味了。

🪂如果你还不会用服务器搭建一个网站,不妨看看这篇文章:「最佳实践」如何用服务器优雅地搭建个人博客网站

我对比了网上几种不错的静态网站生成器后,发现使用 VuePress 搭建知识体系框架很合我的胃口!

👑想想有朝一日要面试的时候,与其从网上拉取各类「面经手册」,还不如就从现在起,搭建一个属于自己的「面试八股文」知识体系框架。

🎯VuePress 简介

VuePress 的诞生初衷是尤大大为了支持 Vue 及其子项目的文档需求。难道不觉得 Vue.js 官网和 VuePress 官网出奇地相似吗?

🚀VuePress 生成的页面都是服务端渲染而来的,也因此具有非常好的加载性能搜索引擎优化(SEO)。同时,一旦页面被加载,Vue 将接管这些静态内容,并将其转换为一个完整的单页应用(SPA),其他页面只会在用户浏览时按需加载。

🥰如果不清楚什么是服务端渲染,可以看这篇文章:彻底理解服务端渲染(SSR)

而且,VuePress 网站是由 VueVue RouterWebpack 驱动的 SPA,如果你熟悉 Vue 知识,甚至可以开发一个自定义主题。

总结下 VuePress 的几个优点:

  • 简洁:以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。
  • Vue 驱动:享受 Vue + WebPack 的开发体验,可以在 Markdown 中使用 Vue 组件,又可以使用 Vue 自定义主题。
  • 高性能:VuePress 会为每个页面预渲染生成静态的 HTML,同时,每个页面被加载的时候,将作为 SPA 运行。
  • 内置 Markdown 拓展语法(下文详谈)
  • 多语言支持 ( locales )
  • 响应式布局
  • 支持 PWA 模式
  • 强大的 Plugin API
  • 基于 Git 的最后更新时间 ( lastUpdated )

👑VuePress 配置流程

安装

VuePress 需要 Node.js >= 8.6 和 npm / yarn 包管理工具

(1)先检查一下 node 版本

node -v

(2)确认版本没问题后,创建并进入新目录

mkdir interview && cd interview

(3)使用自己习惯的包管理工具进行初始化

npm init # yarn init

(4)将 VuePress 安装为本地依赖

官网建议:不使用全局安装 VuePress

npm install -D vuepress # yarn add -D vuepress

注意:如果你的现有项目依赖了 webpack 3.x,我们推荐使用 Yarn (opens new window)而不是 npm 来安装 VuePress。因为在这种情形下,npm 会生成错误的依赖树。

(5)创建第一篇文档

mkdir docs && echo '# Hello VuePress' > docs/README.md

(6)在 package.json 中添加如下脚本配置

"scripts": {
  "docs:dev": "vuepress dev docs",
  "docs:build": "vuepress build docs"
}

(7)本地启动服务器

npm run docs:dev # yarn docs:dev

接下来就可以在 http://localhost:8080/ 中查看文档效果了。

如果有遇到乱码也不用紧张,删除 README.md,重新新建一个然后手动输入 # Hello VuePress 即可。

以上流程就完成了 VuePress 的简单安装,但这远远不够,接下来我们来完成一些基本配置。

基本配置(默认主题配置)

提示:这些基本配置仅对默认主题生效,如果使用自定义主题,选项可能会不同。

目录结构

VuePress 遵循 "约定优于配置" 的理念,推荐以下目录结构:

.
├── docs
│   ├── .vuepress (用于存放全局的配置、组件、静态资源等)
│   │   ├── components (该目录中的 Vue 组件将会被自动注册为全局组件)
│   │   ├── theme (用于存放本地主题)
│   │   │   └── Layout.vue
│   │   ├── public (静态资源目录)
│   │   ├── styles (用于存放样式相关的文件)
│   │   │   ├── index.styl
│   │   │   └── palette.styl
│   │   ├── templates (存储 HTML 模板文件)
│   │   │   ├── dev.html
│   │   │   └── ssr.html
│   │   ├── config.js (配置文件的入口文件)
│   │   └── enhanceApp.js (可选的)
│   │ 
│   ├── README.md (文档首页)
│   ├── guide (存放文章的目录)
│   │   └── README.md
│   └── config.md
│ 
└── package.json

对于上述的目录结构,默认页面路由地址如下:

文件的相对路径页面路由地址
/README.md/
/guide/README.md/guide/
/config.md/config.html

配置站点信息

docs 下创建 .vuepress/ 文件夹,并在该文件夹下创建 config.js 文件作为配置文件的入口文件

mkdir .vuepress && cd .vuepress && touch config.js

docs/.vuepress/config.js 中配置站点信息

module.exports = {
  title: 'Interview',
  description: "专注于分享后端「面试八股文」, 同时收录算法题的题解分析: 包括但不限于 LeetCode、剑指Offer、PTA...",
}

此时网站出现了标题和搜索栏:

内置搜索栏只会为页面的 h1h2h3 以及 tags 构建搜索索引。

如果你需要全文搜索,需要配置添加额外的插件。

首页

docs/README.md 下添加首页信息

---
home: true
heroImage: /images/bk.png
heroText: Interview
tagline: put your bio here
actionText: 快速上手 
actionLink: /zh/guide/
features:
- title: 简洁至上
  details:  Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。
- title: Vue驱动
  details: 享受 Vue + webpack 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。
- title: 高性能
  details: VuePress 为每个页面预渲染生成静态的 HTML,同时在页面被加载的时候,将作为 SPA 运行。
footer: MIT Licensed | Copyright © 2018-present Evan You
---

注:要将 bk.png 图片放到 docs/.vuepress/public/images/ 静态资源目录下,才能使图片生效,其他静态资源也是如此。

添加首页后的效果:

导航栏

docs/.vuepress/config.js 下添加导航栏

// docs/.vuepress.config.js
module.exports = {
  themeConfig: {
    // 是否启用导航栏
    // navbar: false,
    nav: [
      // 跳转站内页面
      { text: '导读', link: '/guide/foreword/' },
      // 嵌套导航
      {
        text: 'Java',
        items: [
          {
            text: 'JavaSE',
            items: [
              { text: '111', link: '/guide/javase/1/' },
              { text: '222', link: '/guide/javase/2/' }
            ]
          },
          {
            text: 'JavaEE',
            items: [
              { text: '111', link: '/guide/javaee/1/' },
              { text: '222', link: '/guide/javaee/2/' }
            ]
          }
        ]
      },
      {
        text: 'Spring',
        items: [
          { text: 'SpringMVC', link: '/guide/springmvc/' },
          { text: 'SpringBoot', link: '/guide/springboot/' },
          { text: 'SpringCloud', link: '/guide/springcloud/' },
        ]
      },
      // 跳转站外地址
      { text: '数据结构与算法', link: 'https://leetcode-cn.com/' },
    ],
  }
}

展示下几种导航栏的效果

侧边栏

docs/.vuepress/config.js 中添加侧边栏

// docs/.vuepress/config.js
module.exports = {
  themeConfig: {
    nav: [ xxx ],
    sidebar: 'auto'
  }
}

sidebar: 'auto' 会根据文章标题自动生成对应的侧边栏,如下图

🚫但是如果这样设置,文章的数量就被导航栏链接个数限制了(也就是说导航栏的每一个链接仅仅对应一篇文章),这显然不是我们想要的结果。

🤩我们想要的应该是如下这种侧边栏:一个导航栏对应一个系列的文章群,然后每一个侧边栏标题对应一篇文章,这样网站的文章可随时添加,又不会显得导航栏很杂乱!

图片截自卡哥网站

🌈不仅要为不同的页面组显示不同的侧边栏,还想将侧边栏划分为多个组。如何实现?官网给出了答案。

下面我们依葫芦画瓢给出一个可践行的解决方案:

module.exports = {
  themeConfig: {
    nav: [
      { text: '前言', link: '/guide/foreword/' },
      {
        text: '数据结构与算法',
        items: [
          { text: 'LeetCode', link: '/guide/leetcode/read.md' },
          { text: '剑指Offer', link: '/guide/剑指offer/' },
          { text: 'PTA', link: '/guide/pta/' }
        ]
      },
      { text: 'GitHub', link: 'https://github.com/Wu-yikun' },
    ],
    // sidebar: 'auto',	// 不使用默认侧边栏
    // 使用自定义侧边栏
    sidebar: {
      "/guide/leetcode/": getBarLeetCode()
    },
  },
}

// /guide/leetcode/ 页面组的侧边栏
function getBarLeetCode() {
  return [
    {
      title: 'LeetCode专栏',
      collapsable: false,
      sidebarDepth: 0,
      children: [
        "read.md"
      ]
    },
    {
      title: '数组',
      collapsable: false,
      sidebarDepth: 0,
      children: [
        "array/14.最长公共前缀.md",
        "array/26.删除有序数组中的重复项.md",
        "array/27.移除元素.md",
        "array/35.搜索插入位置.md",
        "array/66.加一.md",
        "array/88.合并两个有序数组.md"
      ]
    },
    {
      title: '动态规划',
      collapsable: false,
      sidebarDepth: 0,
      children: [
        "dp/118.杨辉三角.md",
        "dp/119.杨辉三角 II.md",
        "dp/121.买股票的最佳时机.md"
      ]
    }
  ]
}

🔎内部文件目录结构一览:

🥴注意:侧边栏的标题不是根据文件名生成的,而是根据文件中的 h1 标题自动生成的!

更多配置

VuePress 的基本配置还有很多,这里就不逐一例举了。

👨‍💻VuePress 其他配置参考:vuepress.vuejs.org/zh/theme/de…

多语言支持

VuePress 还可以配置支持多语言:传送门

🧩插件

安装 katex 插件添加公式支持

npm install markdown-it-katex -D

docs/.vuepress/config.js 中添加插件配置

module.exports = {
  themeConfig: {
    nav: [],
    sidebar: {},
  },
  markdown: {
    lineNumbers: true,
    externalLinks: {
      target: '_blank'
    },
    extendMarkdown: md => {
      md.set({
        html: true
      })
      md.use(require('markdown-it-katex'))
    }
  },
  head: [
    ['link', {
      rel: 'stylesheet',
      href: 'https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.7.1/katex.min.css'
    }],
    ['link', {
      rel: "stylesheet",
      href: "https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/2.10.0/github-markdown.min.css"
    }]
  ]
}

🚀VuePress 插件库:vuepress.vuejs.org/zh/plugin/

🌅Markdown 拓展

因为 Vue 就是以 Markdown 为中心的项目结构,所以支持 Markdown 的所有语法。

此外,VuePress 还额外拓展了一些 Markdown 的用法,类似 GitHub 对 Markdown 的拓展 GFM 一样。

🙄常用的就不提了,我们来说说拓展的语法。

目录

[[toc]]

链接

网站内部的链接,将会被转换成 <router-link> 用于 SPA 导航。同时,站内的每一个文件夹下的 README.md 或者 index.md 文件都会被自动编译为 index.html,对应的链接将被视为 /

内部链接

以如下的文件结构为例:

.
├─ README.md
├─ foo
│  ├─ README.md
│  ├─ one.md
│  └─ two.md
└─ bar
   ├─ README.md
   ├─ three.md
   └─ four.md

假设你现在在 foo/one.md 中:

[Home](/) <!-- 跳转到根部的 README.md -->
[foo](/foo/) <!-- 跳转到 foo 文件夹的 index.html -->
[foo heading](./#heading) <!-- 跳转到 foo/index.html 的特定标题位置 -->
[bar - three](../bar/three.md) <!-- 具体文件可以使用 .md 结尾(推荐) -->
[bar - four](../bar/four.html#标题) <!-- 也可以用 .html -->

自定义容器

::: tip
这是一个提示
:::

::: warning
这是一个警告
:::

::: danger
这是一个危险警告
:::

::: details
这是一个详情块,在 IE / Edge 中不生效
:::

⭐你也可以自定义块中的标题

::: danger STOP
禁止通行
:::

😓该容器效果默认只对默认主题生效,若要在自定义主题中使用,需要配置插件:vuepress-plugin-container

代码块中的行高亮

```java {3}
class Solution {
  public void hello() {
    System.out.println("Hello World!");
  }
}
```

配置行号

你可以通过配置来为每个代码块显示行号

module.exports = {
  markdown: {
    lineNumbers: true
  }
}

Yaml Front Matter

VuePress 提供了对 YAML front matter 开箱即用的支持

---
title: Blogging Like a Hacker
lang: en-US
---

这些数据可以在当前 markdown 的正文,或者是任意的自定义或主题组件中使用。

🚎了解更多,请移步:vuepress.vuejs.org/zh/guide/fr…

Emoji

输入

:tada: :100:

输出:🎉 💯

你可以在 Emoji 库中找到所有的 emoji,其实个人建议使用 Window + . 呼出 emoji 库比较方便。

进阶配置 Markdown

VuePress 使用 markdown-it 来渲染 Markdown,上述大多数的拓展也都是通过自定义的插件实现的。

若想要进一步引入其他配置,则可以在 .vuepress/config.js 中修改 markdown 选项:

上文中支持公式的 markdown-it-katex 插件就是按照该方法修改配置的。

module.exports = {
  markdown: {
    // markdown-it-anchor 的选项
    anchor: { permalink: false },
    // markdown-it-toc 的选项
    toc: { includeLevel: [1, 2] },
    extendMarkdown: md => {
      // 使用更多的 markdown-it 插件!
      md.use(require('markdown-it-xxx'))
    }
  }
}

🌍部署 GitHub Pages

① 在 docs/.vuepress/config.js 中设置正确的 base.

  • 如果你打算发布到 https://<USERNAME>.github.io/,则可以省略这一步,因为 base 默认是 /
  • 👑如果你打算发布到 https://<USERNAME>.github.io/<REPO>/(也就是说你的仓库在 https://github.com/<USERNAME>/<REPO>),那么将 base 设置为 "/<REPO>/"

② 在项目目录下新建 deploy.sh

#!/usr/bin/env sh

# 确保脚本抛出遇到的错误
set -e

# 生成静态文件
npm run docs:build

# 进入生成的文件夹
cd docs/.vuepress/dist

# 如果是发布到自定义域名
# echo 'www.example.com' > CNAME

git init
git add -A
git commit -m 'deploy'

# 注意 📢 修改仓库地址 (下列二选一)
# 如果发布到 https://<USERNAME>.github.io
# git push -f git@github.com:<USERNAME>/<USERNAME>.github.io.git master

# 如果发布到 https://<USERNAME>.github.io/<REPO>
# git push -f git@github.com:<USERNAME>/<REPO>.git master:gh-pages

cd -

执行脚本即可部署到对应仓库 github pages.

🚀未完待续

😥碎碎念:昨天刚用 VuePress 搭建起一个简易的文档架构,今天肝了一整天的文章对昨天一些具体细节进行复盘,这两天的精力都被榨干了。虽然以上的内容不能全面覆盖 VuePress,但也讲得八九不离十,对付对付还是可以的!

😄相信屏幕前的你也跃跃欲试了,那就赶紧实践起来叭!但要记住一点:网站只是载体,文章才是本体;没有优质的文章,再华丽的 UI 界面设计也只是空壳!

😝由于目前「技术栈」仍然有限,「面试八股文」内容仍未接触,所以我的站点可能还需要 1 年左右才能正式上线,计划开设两个站点:「面试八股文」与「算法小册」。

😉如果你觉得本文有哪些错误或者需要补充的地方,欢迎随时在评论区指正。