分析文件夹生成文档页面
2021-04-13
背景
最近小组在做 eslint
相关的升级改造,同时我们需要搭建一个平台,其内容为文档和一些好坏写法的代码展示等。
为了让日后平台的维护者更好的维护文档,或者说只需要编写或删除文档,而不用修改代码,因此需要将文档自动化处理,和代码分离。
- 新增或删除文档只需要在对应的文件夹下新增或删除文档文件即可
- 平台代码
build
的时候会自动处理/docs
文件夹下的文档,生成配置文件,我们只需要在某个文档组件里引用该配置文件即可生成文档页面
由于在内网开发的我也不好截图,但是其效果和 Vue 官网这个效果基本一致:点击顶部某个导航栏,页面左侧为目录层级,右侧为文档信息。
build时处理文档
首先有两个约定:
- 所有的文档都放在
/docs
下,按照目录放好。比如/docs/Vue/基础/安装.md
- 生成的目录结构为:一级为分类,二级为标题,三级为文档下的标题
这个平台技术栈为 Vite
和 Vue
。
markdown to vue
我们需要把 md 文档当成 Vue 组件渲染在页面上,因此配置一下 vite.config.js
:
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import Markdown from 'vite-plugin-md';
export default defineConfig({
plugins: [
vue({
include: [/\.vue$/, /\.md$/],
}),
Markdown({
markdownItSetup(md) {
md.use(require('markdown-it-anchor'));
md.use(require('markdown-it-prism'));
},
}),
],
});
编写脚本,build时处理文档
我的思路如下:
- build 时,分析文档生成目录层级信息和路由信息
- 目录层级信息提供给左侧目录组件渲染左侧目录
- 文档路由和平台现有路由合并
生成目录信息没有什么的难度:
- 读取
/docs
目录生成目录层级,数据结构为树 - markdown 中的标题,可以通过将 markdown 转成 html,通过正则匹配 html 中的 h标签得到
- 最终结果会生成两个配置文件:
文档名.json
和docsRouter.json
其中 文档名.json
内容示例如下,它表示的是左侧的目录层级关系,用于提供给左侧目录组件渲染目录:
// title为显示在左侧的目录标题
// child 为markdown中的标题
// path为该文档的路由
[{
"title": "基础",
"path": "",
"child": [
{
"title": "介绍",
"path": "/docs/test/jichu/jieshao.md",
"child": [
"介绍",
"标题2",
"标题3"
]
},
{
"title": "安装",
"path": "/docs/test/jichu/anzhuang.md",
"child": [
"安装",
"标题2",
"标题3"
]
}
]
},
{
"title": "深入",
"path": "",
"child": [
{
"title": "原理",
"path": "/docs/test/shenru/yuanli.md",
"child": [
"原理",
"标题2",
"标题3"
]
}
]
}]
docsRouter.json
示例如下:
// pathForRouter为路由
// path为某markdown文档的路径
[{
"pathForRouter": "/docs/test/shenru/yuanli.md",
"path": "/docs/test/深入/原理.md",
"content": "这里是文档的内容"
}]
然后在路由配置文件里,写一个小函数将原有的路由配置和现在生成的路由进行合并。文档路由的 component
配置为 import(/docs/test/深入/原理.md)
即可,其余的就交给 Vite 了。
这里有两个细节:
- 生成的路由都是中文文件名的拼音
- 文件中将文档的内容也放了进去,即 content 字段
如果生成的路由是中文的话,比如 /docs/test/深入/原理.md
,那么当你刷新当前路由时,会发现当前页面白屏了。这是因为浏览器会对中文进行编码处理 /docs/test/%E6%B7%B1%E5%85%A5/%E5%8E%9F%E7%90%86.md
,因此刷新时,Vite 找不到编码后的这个路由导致找不到组件。
生成路由信息文件时,顺便将文件内容也放入 json 中,是为了做前端搜索功能。你可以在 Vue 官网上 ctrl+k
体验一下搜索功能,实现效果基本是照它来的。不过Vue 官网的搜索是后端搜索的,我这里做的搜索功能是前端搜索。想必你猜到了,就是将搜索框内的搜索字符串在 docsRouter.json
中进行字符串搜索,因此我可以非常方便的一并将搜索结果对应的文档路由也获取到!因此做结果跳转就非常方便了。
业务代码中使用文档
build 时,已经将所有信息都生成且处理好了,因此在某个页面中使用就很简单了方便了。比如现在 QA.vue
是一个文档展示页面:
// QA.vue
<template>
<side-toc :tocData="tocValue" />
<router-view />
</template>
<script lang="ts">
import { defineComponent } from "vue";
// 这里在导入生成的文档目录数据
import testDoc from '@/toc/test.json';
// 这是左侧目录组件
import SideToc from '@/components/SideToc.vue';
export default defineComponent({
components: {
SideToc
},
setup() {
return {
tocValue: []
}
}
});
</script>