前言
Docusaurus ,是基于 React 驱动的静态网站生成器搭建的文档网站
不过国内 Docusaurus 的资源是真的少。不像 Vuepress。
需求
目前我只懂得官方是通过 BlogListPage 博客列表页根组件来实现的。那么如何实现 Docusaurus 全局读取博客 MarkDown 里的内容呢?
官方的实现方法
首先,在网站目录按照指定要求在 src 文件夹下,新建theme/BlogListPage 等文件夹
代码
import React from "react";
const BlogListPage = (props) => {
console.log('====>props:', props);
const { metadata, items } = props;
return (
<> </>
)
}
export default BlogListPage
那么有什么办法实现全局的 data 呢?我们接着往下看
自写 BlogListPage 插件,实现全局读取
至于全局数据抓取,我还得感谢 愧怍 通过他的思路和指点,我算是弄懂了如何实现全局数据。
首先我们在 src 文件下,创建 plugin/plugin-content-blog 文件夹,分别创建 type.ts 和 index.ts
`type.ts 通过引入源码的实现的思路去强制 index.ts 需要的类型
index.ts 主要通过官方插件使用的方法来实现的,拿到值后,通过 setGlobalData 函数存取到全局数据中。
其次,由于 Docusaurus 只支持加载 js 文件,需要将 ts 文件打包或者转成 js 文件。由于打包比较麻烦,我就采用了 ts 转 js 的方式。具体方法如下:
-
在终端输入指令:
npm install -g typescript即可。 -
在终端输入指令,找到 网站 plugin 目录下 plugin-content-blog 文件夹
如:
cd dome/my-website/src/plugin/plugin-content-blog -
然后
tsc index.ts,你就发现 plugin-content-blog 目录会生产 index.js 和 type.js 等文件
最后,配置 docusaurus.config.js,把官方默认的 blog 给 false 掉,然后在插件的配置方法中引入我们写自己的插件
path.resolve(__dirname, './src/plugin/plugin-content-blog')
presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
sidebarPath: require.resolve('./sidebars.js'),
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/xxx',
},
blog: false, // 把原来的 blog 插件给关了
// blog: {
// showReadingTime: true,
// // Please change this to your repo.
// // Remove this to remove the "edit this page" links.
// editUrl:
// 'https://github.com/xxx',
// },
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
}),
],
],
引入配置好的插件
plugins: [
[
path.resolve(__dirname, './src/plugin/plugin-content-blog'), {
path: 'blog',
editLocalizedFiles: false,
blogSidebarTitle: '近期文章',
blogSidebarCount: 10,
postsPerPage: 10,
showReadingTime: true,
readingTime: ({ content, frontMatter, defaultReadingTime }) =>
defaultReadingTime({ content, options: { wordsPerMinute: 300 } }),
}
],
],
官方插件使用方法的介绍 docusaurus.io/zh-CN/docs/…
// @ts-check
// Note: type annotations allow type checking and IDEs autocompletion
const lightCodeTheme = require('prism-react-renderer/themes/github');
const darkCodeTheme = require('prism-react-renderer/themes/dracula');
const path = require('path')
/** @type {import('@docusaurus/types').Config} */
const config = {
title: 'My Site',
tagline: 'Dinosaurs are cool',
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico',
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name.
// Even if you don't use internalization, you can use this field to set useful
// metadata like html lang. For example, if your site is Chinese, you may want
// to replace "en" with "zh-Hans".
// i18n: {
// defaultLocale: 'en',
// locales: ['en'],
// },
i18n: {
defaultLocale: 'en',
locales: ['en', 'zh-Hans', 'fa'],
localeConfigs: {
en: {
htmlLang: 'en-GB',
},
// 如果你不需要覆盖默认值,你可以忽略这个语言(比如 zh-Hans)
fa: {
direction: 'rtl',
},
},
},
presets: [
[
'classic',
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
sidebarPath: require.resolve('./sidebars.js'),
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/xxx',
},
blog: false, // 把原来的 blog 插件给关了
// blog: {
// showReadingTime: true,
// // Please change this to your repo.
// // Remove this to remove the "edit this page" links.
// editUrl:
// 'https://github.com/xxx',
// },
theme: {
customCss: require.resolve('./src/css/custom.css'),
},
}),
],
],
plugins: [
[
path.resolve(__dirname, './src/plugin/plugin-content-blog'), {
path: 'blog',
editLocalizedFiles: false,
blogSidebarTitle: '近期文章',
blogSidebarCount: 10,
postsPerPage: 10,
showReadingTime: true,
readingTime: ({ content, frontMatter, defaultReadingTime }) =>
defaultReadingTime({ content, options: { wordsPerMinute: 300 } }),
}
],
],
themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
navbar: {
title: 'My Site',
logo: {
alt: 'My Site Logo',
src: 'img/logo.svg',
},
items: [
{
type: "localeDropdown",
position: "left",
},
{
type: 'doc',
docId: 'intro',
position: 'left',
label: 'Tutorial',
},
// {to: '/blog', label: 'Blog', position: 'left'},
{
href: 'https://github.com/facebook/docusaurus',
label: 'GitHub',
position: 'right',
},
],
},
footer: {
style: 'dark',
links: [
{
title: 'Docs',
items: [
{
label: 'Tutorial',
to: '/docs/intro',
},
],
},
{
title: 'Community',
items: [
{
label: 'Stack Overflow',
href: 'https://stackoverflow.com/questions/tagged/docusaurus',
},
{
label: 'Discord',
href: 'https://discordapp.com/invite/docusaurus',
},
{
label: 'Twitter',
href: 'https://twitter.com/docusaurus',
},
],
},
{
title: 'More',
items: [
{
label: 'Blog',
to: '/blog',
},
{
label: 'GitHub',
href: 'https://github.com/facebook/docusaurus',
},
],
},
],
copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`,
},
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
},
}),
};
module.exports = config;
type.ts
// type.ts
import type {BrokenMarkdownLink, ContentPaths} from '@docusaurus/utils';
import type {BlogPostMetadata} from '@docusaurus/plugin-content-blog';
// @ts-ignore
import type {Tag} from '@docusaurus/types';
// @ts-ignore
import type {Metadata as BlogPaginatedMetadata} from '@theme/BlogListPage';
export type BlogContentPaths = ContentPaths;
export type BlogContent = {
blogSidebarTitle: string;
blogPosts: BlogPost[];
blogListPaginated: BlogPaginated[];
blogTags: BlogTags;
blogTagsListPath: string;
};
export type BlogTags = {
[permalink: string]: BlogTag;
};
export type BlogTag = Tag & {
/** Blog post permalinks. */
items: string[];
pages: BlogPaginated[];
};
export type BlogPost = {
id: string;
metadata: BlogPostMetadata;
content: string;
};
export type BlogPaginated = {
metadata: BlogPaginatedMetadata;
/** Blog post permalinks. */
items: string[];
};
export type BlogBrokenMarkdownLink = BrokenMarkdownLink<BlogContentPaths>;
export type BlogMarkdownLoaderOptions = {
siteDir: string;
contentPaths: BlogContentPaths;
truncateMarker: RegExp;
sourceToPermalink: {[aliasedPath: string]: string};
onBrokenMarkdownLink: (brokenMarkdownLink: BlogBrokenMarkdownLink) => void;
};
index.ts
import {LoadContext, Plugin} from '@docusaurus/types';
import * as blogPluginExports from '@docusaurus/plugin-content-blog';
import type {PluginOptions} from '@docusaurus/plugin-content-blog';
import {BlogContent} from './types';
const blogPlugin = blogPluginExports.default;
async function blogPluginEnhanced(
context: LoadContext,
options: PluginOptions,
): Promise<Plugin<BlogContent>> {
const blogPluginInstance: any = await blogPlugin(context, options);
return {
• ...blogPluginInstance,
• async contentLoaded({content, actions}) {
• // Create default plugin pages
• await blogPluginInstance.contentLoaded({content, actions});
• // Create your additional pages
• const {blogPosts, blogTags} = content;
• const {setGlobalData} = actions;
• setGlobalData({
• blogs: blogPosts,
• tags: blogTags,
• });
• },
};
}
module.exports = {
...blogPluginExports,
default: blogPluginEnhanced,
};
怎么使用全局 blog 数据
在任意组件中,使用 useGlobalData 函数来获取。具体步骤如下
import React from "react";
import useGlobalData from "@docusaurus/useGlobalData";
const Home = () => {
const globalData = useGlobalData();
const blogPluginData = globalData?.['docusaurus-plugin-content-blog']?.[
'default'
]
console.log('全局博客的内容:', blogPluginData);
return (
<></>
)
}
export default Home
以上就是实现全局读取博客内容的方法了,至于读取全局文档的,思路也差不多,但是我只读到标题和描述之类的,内容还没有抓到,如果你有更好的方法,希望能指点一下。