Docusaurus
开始
Docusaurus 是一个基于 React 构建的帮助快速生成静态网站的工具,支持将 MDX 格式编写的文档生成静态 HTML 文件,同时还支持在 Markdown 中嵌入 React 组件。
什么情况下你能用到它?
- 使用 markdown 语法书写静态博客;
- 构建一个文档类的站点;
- 一个带有新闻功能和静态页面为主的官方网站;
- 建立一个实时代码演示效果的教程类的网站;
- 集成搜索的个人知识库。
如何使用?
安装
npx create-docusaurus@latest my-website classic
运行
cd my-website
npx docusaurus start
使用指南
我将从博客、文档、页面几个方面详细介绍如何使用 Docusaurus 搭建一个满足各个需求的站点。
官方文档:
注意事项
- 修改
sidebars.js
文件,在开发模式下,一定要重新启动才能生效。
全局配置
关于 Docusaurus 应用的的配置项很多(也就是根目录下的 docusaurus.config.js
文件),官方文档很难覆盖到所有的,或者有所提到但是也很隐蔽,所以我把常用的一些配置做些讲解。
网站顶部公告
例如官网的顶部这样一条信息栏,是通过 themeConfig
下面的参数 announcementBar
配置而来。
如果你的网站有醒目的公告消息需要展示,可以开启这个配置,公告的内容是支持 html
文本的。样式当然也是可以自定义的,官网上的背景是经过自定义的,默认背景是白色的。
docusaurus.config.js
themeConfig: {
announcementBar: {
id: 'announcementBar-3',
content: `🎉️ <b>我的<a target="_blank" href="https://spacexcode.com/routes">足迹</a> 应用上线了!</b> 👣`,
},
}
导航栏和底部菜单支持插入 Html 代码
导航栏和底部菜单都支持更灵活的自定义 html
代码的格式。
docusaurus.config.js
themeConfig: {
navbar: {
items: [
{
label: '关于',
position: 'right',
items: [
{ to: '/about', label: '关于本站' },
{ to: '/author', label: '了解作者' },
{ to: '/release/log', label: '更新日志' },
{ type: 'html', value: '<hr class="dropdown-separator">' }
]
}
]
},
footer: {
links: [
{
title: '常用技术',
items: [
{ label: 'TypeScript', href: 'https://www.typescriptlang.org/' },
{ label: 'Vue', href: 'https://cn.vuejs.org' },
{
html: `
<a href="https://www.netlify.com" target="_blank" rel="noreferrer noopener" aria-label="Deploys by Netlify">
<img src="https://www.netlify.com/img/global/badges/netlify-color-accent.svg" alt="Deploys by Netlify" width="114" height="51" />
</a>`
}
],
}
]
}
}
博客功能
Docusaurus 中的功能如博客、文档或页面都是由插件提供,而博客功能由插件 plugin-content-blog
提供支持。
安装博客功能插件
它的安装命令:
npm install --save @docusaurus/plugin-content-blog
一般安装 Docusaurus 应用默认自带博客插件的,无需额外安装。
安装好之后,项目根目录下有个 blog
目录,然后在配置文件中添加导航菜单,或者直接通过 https://域名/blog
访问博客首页列表页面。
module.exports = {
themeConfig: {
// ...
navbar: {
items: [
// ...
{to: 'blog', label: '博客', position: 'left'}, // or position: 'right'
],
},
},
};
添加博文
在 blog
目录下创建 my-first-blog.md
文件,也可以是 mdx
后缀文件,以下是一篇博文的内容格式简介:
---
title: 我的第一篇博文
description: 这是关于本篇博文的描述文字。
slug: my-first-blog
authors:
- name: Timfan
title: 高级前端开发
url: https://github.com/fantingsheng
image_url: https://spacexcode.com/img/avatar.png
tags: [标签一, 标签二]
image: https://i.imgur.com/mErPwqL.png
hide_table_of_contents: false
---
这是文章的正文部分。。。
<!-- truncate -->
这段文字只有在文章详情页才能看到
<!-- truncate -->
这个标签的作用是在正文中截取一部分文字作为列表页的文章简介显示。没有该标签,列表页面会显示全文。
文章的前置部分参数更多的详见 API 文档
这里讲解几个有代表性的
date
:文章的创建时间,默认从文件名或者目录名中获取,比如:2023-10-09-blog-post.md
,2023-10-09-blog-post/index.md
,2023/10/09/blog-post.md
, 如果文章前置部分没有定义date
参数,文件和目录名中也不包含日期,则从该文件的创建时间推断出。draft
:该参数一旦设置为true
,则文章只会在开发模式中显示,也就是常见的草稿状态。unlisted
:设置该参数为true
时,在开发环境和发布环境的列表页中都无法显示该文章,区别于draft
参数,它可以通过文章链接访问,同时在sitemaps
文件中 也不包含该文章。hide_table_of_contents
:隐藏右侧的标题目录。
博客列表页
博客列表页的左侧最近文章标题通过 blogSidebarTitle
参数设置,数量通过 blogSidebarCount
配置。
module.exports = {
// ...
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
},
blog: {
blogTitle: '博客',
blogDescription: '前端开发知识总结分享',
blogSidebarTitle: '最近文章',
showReadingTime: true,
postsPerPage: 8,
blogSidebarCount: 15
}
}
]
]
}
默认列表页每页显示10篇文章,如果你设置 postsPerPage: 'ALL'
,则所有的文章都在第一页显示,也就没有了所谓的分页导航。
文章发布时间
上面已经提到文章的发布时间可以通过 date
参数设置或者从文件名或者目录名推断。如果我们不想让所有的文章都处在 blog
目录下,可以把文章 YYYY/MM/DD/my-blog-post-title.md
这样按 年/月/日
分目录存放。
这里有个问题,列表页的文章排列顺序是通过发布日期来排列的,如果在某一天发布多篇文章,那么如何决定这几篇文章的排列顺序呢?可以设置 date
参数格式日期到时间。
---
date: 2021-09-13T10:00
---
文档的实现
文档功能由插件 plugin-content-docs
提供支持。它也是 Docusaurus 的默认插件。所以你创建的应用默认包含文档功能。
创建文档
项目根目录下的 docs
为存放文档的目录,你可以直接在里面创建 md
或 mdx
文件,也可以新建子目录以更多维度地组织你的文档。
docs # 文档根目录
├── javascript
│ └── example.md
├── css
│ └── index.mdx
├── intro.mdx
├── ...
提示
文档目录下所有以 _
前缀来命名的文件都会被视为局部的文件,不会渲染成新的页面。
这种局部文件的使用方式:
import PartialExample from './_markdown-partial-example.mdx';
<PartialExample name="Sebastien" />
文档的访问链接
文档的访问链接默认是根据你文件的存放路径来的,比如:
路径 | 访问链接 |
---|---|
docs/intro.mdx | http://域名/docs/intro |
docs/javascript/example.md | http://域名/docs/javascript/example |
如果你不想直接用文件名来作为访问链接的最后部分,你需要在文档的导言的 id
字段中定义:
---
id: my-first-doc
title: 一篇包含标签的文档
description: 文档的描述文字
---
或者你想在链接中直接跳过目录,还有一个 slug
字段。比如 docs/css/guide.mdx
---
id: guide
title: 一篇包含标签的文档
slug: /
---
则该文档的访问链接为 http://域名/docs/guide
侧边栏
文档的侧边栏配置文件为项目根目录下的 sidebars.js
文件,然后通过 docusaurus.config.js
配置文件中的 sidebarPath
属性进行挂载。
module.exports = {
// ...
presets: [
[
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
}
}
]
]
}
下面以当前站点为例,导航中的“知识库”、“代码片段”和“专题”分别对应三个文档。它们分别有自己对应的侧边栏,在配置文件中有三个分类:knSidebar
, snipSidebar
,topicSidebar
。
文档存放目录结构:
docs # 文档根目录
├── javascript
│ └── example.md
├── css
│ └── index.mdx
├── snippet # 代码片段目录
│ └── component
│ └── index.mdx
├── topic # 专题目录
│ └── docusaurus
│ └── some.mdx
├── ...
对应侧边栏配置
const sidebars = {
knSidebar: [ // 知识库
'index',
{
type: 'category',
label: 'JavaScript',
items: [
{
type: 'autogenerated',
dirName: 'javascript'
}
],
link: {
type: 'generated-index',
title: 'JavaScript',
description: 'JavaScript(JS)是一种具有函数优先特性的轻量级、解释型或者说即时编译型的编程语言。',
slug: '/javascript',
keywords: ['JavaScript', '前端', '浏览器'],
}
},
{
type: 'category',
label: 'CSS',
items: [
{
type: 'autogenerated',
dirName: 'css'
}
]
},
{
type: 'category',
label: 'NodeJS',
items: [
{
type: 'autogenerated',
dirName: 'nodejs'
}
]
},
'typescript',
'framework',
{
type: 'category',
label: 'Vue',
items: [
{
type: 'autogenerated',
dirName: 'vue'
}
],
link: {
type: 'generated-index',
title: 'Vue',
description: '渐进式JavaScript 框架,易学易用,性能出色,适用场景丰富的 Web 前端框架。',
slug: '/vue',
keywords: ['渐进式', '框架', '响应式'],
}
},
{
type: 'category',
label: 'React',
items: [
{
type: 'autogenerated',
dirName: 'react'
}
]
},
{
type: 'category',
label: '工程化',
items: [
{
type: 'autogenerated',
dirName: 'workflow'
}
]
},
{
type: 'category',
label: '服务器',
items: [
{
type: 'autogenerated',
dirName: 'server'
}
]
},
{
type: 'category',
label: '整理合集',
items: [
{
type: 'autogenerated',
dirName: 'collection'
}
]
},
{
type: 'category',
label: '在线演示',
items: [
{
type: 'autogenerated',
dirName: 'demo'
}
]
},
{
type: 'category',
label: '资源',
items: [
{
type: 'autogenerated',
dirName: 'source'
}
]
}
],
snipSidebar: [ // 代码片段
'snippet/intro',
{
type: 'category',
label: '小功能',
items: [
{
type: 'autogenerated',
dirName: 'snippet/function'
}
],
link: {
type: 'generated-index',
title: '小功能',
description: '小功能,大用处。',
slug: '/snippet/function',
keywords: ['小功能', '封装', '常用函数'],
}
},
{
type: 'category',
label: '小组件',
items: [
{
type: 'autogenerated',
dirName: 'snippet/component'
}
],
link: {
type: 'generated-index',
title: '小组件',
description: '收集制作的一些小组件,有的已经在本站中使用。',
slug: '/snippet/component',
keywords: ['组件', '封装', '常用函数'],
}
},
{
type: 'category',
label: '钩子函数',
items: [
{
type: 'autogenerated',
dirName: 'snippet/hooks'
}
],
link: {
type: 'generated-index',
title: '钩子函数',
description: '常用的封装好的 hooks,拿来即用。',
slug: '/snippet/hooks',
keywords: ['钩子', '封装', 'Hook'],
}
},
{
type: 'category',
label: '小程序',
items: [
{
type: 'autogenerated',
dirName: 'snippet/program'
}
],
link: {
type: 'generated-index',
title: '小程序',
description: '用代码实现某个特定功能的或解决某个特定问题的小程序,从某种意义上说就是一个软件产品。',
slug: '/snippet/program',
keywords: ['程序', '功能', '解决方案'],
}
},
],
topicSidebar: [ // 专题
'topic/intro',
{
type: 'category',
label: 'Docusaurus',
items: [
{
type: 'autogenerated',
dirName: 'topic/docusaurus'
}
]
},
{
type: 'category',
label: 'Next.js',
items: [
{
type: 'autogenerated',
dirName: 'topic/nextjs'
}
]
}
]
}
隐藏侧边栏
有的时候你可能需要暂时收起侧边栏,将视线集中在内容区域。配置 sidebar
参数的 hideable
属性,该值默认为 false
,当设置为 true
时,这时侧边栏下面会出现一个向左 的箭头按钮。该按钮实现侧边栏的收起功能。
module.exports = {
themeConfig: {
docs: {
sidebar: {
hideable: true,
},
},
},
};
侧边栏的展开方式
当你的文档侧边栏层级过多,为了关注选定的部分,免于打开过多的菜单,当我们打开一个同级下的一个菜单,其它菜单会收起。
module.exports = {
themeConfig: {
docs: {
sidebar: {
autoCollapseCategories: true,
},
},
},
};
侧边栏默认展开
侧边栏默认是折叠状态,但可以通过参数设置进入文档,及展开某个侧边栏项,也可通过全局参数设置所有的文档侧边栏项初始就是展开的状态。
先说全局设置:
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
sidebarCollapsed: false,
},
},
],
],
};
再说局部对某个侧边栏项:
topicSidebar: [
{
type: 'category',
label: 'Docusaurus',
collapsed: false,
items: [
{
type: 'autogenerated',
dirName: 'topic/docusaurus'
}
]
}
]
以上两种只是将侧边栏菜单设置成默认展开状态,右侧的折叠操作按钮仍然存在。还有一种设置选项是将菜单设置成不可折叠的状态,及永远是展开状态,操作按钮都不存在了。
topicSidebar: [
{
type: 'category',
label: 'Docusaurus',
collapsible: false,
items: [
{
type: 'autogenerated',
dirName: 'topic/docusaurus'
}
]
}
]
注意:开发环境下修改侧边栏配置文件
sidebars.js
后需要重启才能看到效果。
传递自定义参数
如果我们想更多地定制侧边栏的功能和样式,就需要从侧边栏的配置文件中传递参数,然后通过 Swizzle
侧边栏组件,进行改造。比如这样一个常见的功能,给某个文档“标新”操作,即在 菜单右上角显示 new 标识。
{
type: 'category',
label: 'Next.js',
items: [
{
type: 'autogenerated',
dirName: 'topic/nextjs',
}
],
customProps: {
featured: true
}
};
执行 Swizzle 安装命令
npm run swizzle @docusaurus/theme-classic DocSidebarItem --eject
这时在 src/theme
目录下生成 DocSidebarItem
目录,我们编辑 Category/index.js
文件
在原来的 155
行修改
-- {label}
++ {label}
++ { customProps && customProps.featured ?
++ <sup><img src='/img/new.png' width='10'style={{ verticalAlign: 'top', marginLeft: '2px' }} /></sup> : '' }
最终的效果:
独立页面
页面功能由插件 plugin-content-pages
提供支持。它也是 Docusaurus 的默认插件。所以你创建的应用默认包含页面功能。
在位于项目的根目录下有个 pages
目录,你不仅可以使用 md/mdx
格式的文件来生成独立页面,更可以使用 React 代码来建立页面。
页面布局
如果你的页面是以 mdx
文件生成的,则它是默认包含网站公共的头部导航和底部的。
而如果你的页面是通过新建的 jsx
代码生成的,它是不包含公共部分的。你需要导入 Layout
组件。
import React from 'react';
import Layout from '@theme/Layout';
import Head from '@docusaurus/Head';
export default function () {
return (
<Layout title='城市印象' description='记录自己的城市风景,居一城,爱一城'>
<Head>
<meta name='keywords' content='城市, 风景, 无锡, 随手拍, 江南, 太湖' />
</Head>
</Layout>
{/* ... */}
)
}
比如本站的足迹 https://spacexcode.com/routes 页面就是一个不包含公共头部和底部的页面。
import React from 'react';
import Head from '@docusaurus/Head';
export default function () {
return (
<>
<Head>
<meta name="title" content='我的足迹' />
<meta name="keywords" content='足迹,跑步,金城湾,尚贤湖,Strava,运动' />
</Head>
{/* ... */}
</>
)
}
功能插件
Sass/SCSS 支持
安装插件
npm install --save docusaurus-plugin-sass sass
在配置文件 docusaurus.config.js
中增加配置项:
export default {
// ...
plugins: ['docusaurus-plugin-sass'],
// ...
};
开发自定义插件
// 创建一个新的npm包,作为插件项目的代码库
npx tsdx create docusaurus-plugin-template
// 进入新创建的插件项目目录
cd docusaurus-plugin-template
// 添加Docusaurus的类型定义
yarn add --dev @docusaurus/types@2.0.0-alpha.65
// 编写插件的代码
// src/index.ts
import { LoadContext, Plugin } from '@docusaurus/types';
function myDocusaurusPlugin({ siteConfig: { themeConfig }}: LoadContext): Plugin<void> {
// 在这里编写你的插件逻辑
return {
name: 'my-docusaurus-plugin',
// ...其他生命周期方法
};
}
export default myDocusaurusPlugin
// 在本地测试你的插件
yarn build
yarn link
// 在你的Docusaurus项目中使用你的插件
cd /path/to/your/docusaurus/project
yarn link docusaurus-plugin-template
// 修改docusaurus.config.js,引入你的插件
module.exports = {
// ...
plugins: ['docusaurus-plugin-template'],
};
// 发布你的插件到npm
npm publish
社区收集汇总的优秀的插件