0%

文档站点的分析及选型

一个组件库一般是有官方的文档站点的, 我们的组件库现在是没有官方文档站点的,因此我们的组件库应该要有官方文档站点。

那么怎么做? 我们可以参考现成的流行方案。

那么现在有哪些流行方案呢?根据我在互联网的粗略检索,我认为现成的流行方案大致可以分为以下两种:

分析

从这两个项目的官网上可以看到, 一个文档站点由以下几个主要部分组成:

  • 顶部导航栏
  • 侧边栏大纲
  • 文章主体

而顶部导航栏除去导航功能外,还包括语义化版本本地化和国际化、 项目仓库地址、主题以及站点搜索。

侧边栏生成

侧边栏大纲部分是根据文章标题等级自动生成的,其生成算法大概同下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
type heading = 'H1' | 'H2' | 'H3' | 'H4' | 'H5' | 'H6'

const getHeadingList = [...document.querySelectorAll('h1, h2, h3, h4, h5, h6')].map((it) => {
// do something
return it.nodeName
})

const logCount = ((
time = 0
) => (message = '') => void console.log(`${message}${++time}`))()

const heading2Menu = (headings: heading[]) => {
// O(n)
const toTree = (
ref = {
type: 'root',
result: [],
rootLevel: 0,
prevLevel: 0,
headings: [...headings],
}
) => {
let { type, result, headings, rootLevel, prevLevel } = ref

logCount(`headings.length: ${headings.length}, toTree() count:`)

const isRoot = type === 'root'
const _result: result = isRoot ? result : []

while (headings.length !== 0) {
const heading = headings[0]
const level = Number(heading.slice(1))

if (!isRoot && (level <= rootLevel || level <= prevLevel)) break

if (isRoot) rootLevel = level

headings.shift()

_result.push({
name: heading,
childs: toTree({
type: 'child',
result,
rootLevel,
prevLevel: level,
headings,
}),
})
}

return _result
}

return toTree()
}

最后是文章主体。我们知道开发文档一般采用 markdown 文档格式进行编写,而站点网站的主要功能就是根据 markdown 文档生成静态 HTML。

markdown 解析器

根据 markdown 文档生成静态 HTML,这是 markdown 解析器所做的工作。

无论是 docusaurus 所采用的 remarkable 解析器,还是 vuepress 所采用的 markdown-it 解析器,它们都是 commonmark-spec 的实现, 因此架构上大同小异。

组成部分

markdown 解析器一般由 parser 和 render 两大部分组成。

parser 的工作大概就是载入 markdown 文件然后逐个字符读取,根据读取到的不同字符串应用不同的规则生成 token, 然后将该 token push 到最后要返回的 tokens 数组中。

render 的工作大概就是拿到 parser 的解析结果既 tokens,根据不同的 token 应用不同的规则生成 HTML string。

工作原理

这一时半会说不清楚,请参考: https://juejin.cn/post/6844903834041450510

语义化版本

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  • 主版本号:当你做了不兼容的 API 修改,
  • 次版本号:当你做了向下兼容的功能性新增,
  • 修订号:当你做了向下兼容的问题修正。
  • 先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。

组件库有很多版本因此其文档也需要版本化,更多请参考 https://docusaurus.io/zh-CN/docs/versioning

本地化和国际化

本地化(通常缩写为 L10n)能够使网站、Web应用或任何其他形式的内容适用于特定语言的范围和文化圈。国际化(通常缩写为 I18n)被设计用来使网站或应用程序尽可能的实现本地化。

没什么好说的 请参考 https://docusaurus.io/zh-CN/docs/i18n/crowdin 与 https://docusaurus.io/zh-CN/docs/i18n/git

站点搜索

一个好的站点搜索可以让我们快速定位到我们要找的文档内容,大大提高我们的检索效率。

请参考 algolia

主题

主题分为站点主题和代码主题。

站点主题

docusaurus 提供了白天与黑夜两种模式,可以在导航栏右侧的主题按钮点击进行切换。

而 vue 则有官方和社区提供的主题包可供导入使用。

除此之外,主题还有布局和功能上的变化。 

更多请参考 https://docusaurus.io/zh-CN/docs/api/themes 和 https://vuepress.vuejs.org/zh/theme/

代码主题

由于 markdown 最终被解析渲染成 HTML, 因此开源社区主流的代码高亮库,如 highlight.jsprismshiki 等就可以应用在此处。

highlight.jsprism 都是在代码文本中插入标签包裹需要高亮的元素并通过 CSS 文件来设置高亮样式,而 shiki,一个基于 TextMate 语法的代码高亮器。它直接生成带样式的包裹元素,所以不需要引入额外的 CSS 文件。

更多请参考 https://cn.sli.dev/custom/highlighters.html#highlighters

一般 markdown 解析器都提供了代码主题的配置选型,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Remarkable } from 'remarkable'
import hljs from 'highlight.js' // https://highlightjs.org/

// Actual default values
const md = new Remarkable({
highlight (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value;
} catch (err) {}
}

try {
return hljs.highlightAuto(str).value;
} catch (err) {}

return '' // use external default escaping
}
})

PWA

PWA(Progressive Web Apps,渐进式 Web 应用)运用现代的 Web API 以及传统的渐进式增强策略来创建跨平台 Web 应用程序。这些应用无处不在、功能丰富,使其具有与原生应用相同的用户体验优势。这组文档和指南告诉您有关 PWA 的所有信息。

部署

最后是站点的部署,一般部署到项目源码仓库免费的 github pages 上即可。

请参考: https://docusaurus.io/zh-CN/docs/deployment

选型

docusaurusvuepress 都是非常优秀的开源文档站点项目,但由于开发团队主要使用 react 技术栈,最后选用了 docusaurus

扩展阅读