跳到主要内容

生命周期 API

在构建过程中,插件并行加载以获取其自身内容并将其呈现到路由中。插件也可以配置 webpack 或对生成的 文件进行后处理。

async loadContent()

插件应使用此生命周期从数据源(文件系统、远程 API、无头 CMS 等)获取数据或进行一些服务器处理。返回值 是它需要的內容。

例如,下面的插件返回 1 到 10 之间的随机整数作为内容。

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'docusaurus-plugin',
async loadContent() {
return 1 + Math.floor(Math.random() * 10);
},
};
}

async contentLoaded({content, actions})

contentLoaded 中将使用在 loadContent 中加载的数据。它可以呈现到路由、注册为全局数据等。

content

loadContent 完成后将调用 contentLoadedloadContent() 的返回值将作为 content 传递给 contentLoaded

actions

actions 包含三个函数:

addRoute(config: RouteConfig): void

创建一个要添加到网站的路由。

export type RouteConfig = {
/**
* 带前导斜杠。尾随斜杠将由配置标准化。
*/
path: string;
/**
* 用于呈现此路由的组件,捆绑程序可以 `require` 的路径。
*/
component: string;
/**
* 属性。每个条目应为 `[propName]: pathToPropModule`(使用 `createData` 创建)
*/
modules?: RouteModules;
/**
* 路由上下文将包装 `component`。使用 `useRouteContext` 检索此处声明的内容。请注意,此处声明的所有自定义路由上下文都将在 {@link RouteContext.data} 下命名空间。
*/
context?: RouteModules;
/**
* 嵌套路由配置,对于具有子路由的“布局路由”很有用。
*/
routes?: RouteConfig[];
/**
* React 路由器配置选项:`exact` 路由不会匹配子路由。
*/
exact?: boolean;
/**
* React 路由器配置选项:`strict` 路由对尾随斜杠的存在敏感。
*/
strict?: boolean;
/**
* 用于对路由进行排序。
* 优先级较高的路由将首先匹配。
*/
priority?: number;
/**
* 可选路由元数据
*/
metadata?: RouteMetadata;
/**
* 额外的属性;将在客户端可用。
*/
[propName: string]: unknown;
};

/**
* 插件作者可以为创建的路由分配额外的元数据
* 它仅在 Node.js 端可用,不会发送到浏览器
* 可选:鼓励但不要求插件作者提供它
*
* 一些插件可能会使用此数据来提供附加功能。
* 这是站点地图插件提供“lastmod”支持的情况。
* 另请参阅:https://github.com/facebook/docusaurus/pull/9954
*/
export type RouteMetadata = {
/**
* 导致创建当前路由的源代码文件路径
* 在官方内容插件中,这通常是 Markdown 或 React 文件
* 此路径应相对于站点目录
*/
sourceFilePath?: string;
/**
* 此路由的上次更新日期
* 这通常是从 sourceFilePath 的 Git 历史记录中读取的
* 但也可以通过其他方式提供(通常是前题)
*
* 这尤其是在为站点地图插件添加“lastmod”支持时引入的,请参阅 https://github.com/facebook/docusaurus/pull/9954
*/
lastUpdatedAt?: number;
};

type RouteModules = {
[module: string]: Module | RouteModules | RouteModules[];
};

type Module =
| {
path: string;
__import?: boolean;
query?: ParsedUrlQueryInput;
}
| string;

createData(name: string, data: any): Promise<string>

一个声明性回调,用于创建静态数据(通常是 JSON 或字符串),稍后可以将其作为属性提供给您的路由。获取要存储的文件名和数据,并返回实际数据文件的路径。

例如,下面的插件创建一个显示“您的朋友是:杨舜、塞巴斯蒂安”的 /friends 页面:

website/src/components/Friends.js
import React from 'react';

export default function FriendsComponent({friends}) {
return <div>Your friends are {friends.join(',')}</div>;
}
docusaurus-friends-plugin/src/index.js
export default function friendsPlugin(context, options) {
return {
name: 'docusaurus-friends-plugin',
async contentLoaded({content, actions}) {
const {createData, addRoute} = actions;
// 创建 friends.json
const friends = ['Yangshun', 'Sebastien'];
const friendsJsonPath = await createData(
'friends.json',
JSON.stringify(friends),
);

// 添加 '/friends' 路由,并确保它接收 friends 属性
addRoute({
path: '/friends',
component: '@site/src/components/Friends.js',
modules: {
// propName -> JSON 文件路径
friends: friendsJsonPath,
},
exact: true,
});
},
};
}

setGlobalData(data: any): void

此函数允许创建一些全局插件数据,可以从任何页面(包括其他插件创建的页面和主题布局)读取。

此数据可以通过 useGlobalDatausePluginData hook 访问您的客户端/主题代码。

注意

全局数据是……全局的:其大小会影响您网站所有页面的加载时间,因此请尽量保持其体积小巧。尽可能优先使用 createData 和特定于页面的数据。

例如,下面的插件创建一个显示“您的朋友是:杨舜、塞巴斯蒂安”的 /friends 页面:

website/src/components/Friends.js
import React from 'react';
import {usePluginData} from '@docusaurus/useGlobalData';

export default function FriendsComponent() {
const {friends} = usePluginData('docusaurus-friends-plugin');
return <div>Your friends are {friends.join(',')}</div>;
}
docusaurus-friends-plugin/src/index.js
export default function friendsPlugin(context, options) {
return {
name: 'docusaurus-friends-plugin',
async contentLoaded({content, actions}) {
const {setGlobalData, addRoute} = actions;
// 创建 friends 全局数据
setGlobalData({friends: ['Yangshun', 'Sebastien']});

// 添加 '/friends' 路由
addRoute({
path: '/friends',
component: '@site/src/components/Friends.js',
exact: true,
});
},
};
}

configureWebpack(config, isServer, utils, content)

修改内部 webpack 配置。如果返回值是 JavaScript 对象,它将使用 webpack-merge 合并到最终配置中。如果它是一个函数,它将被调用并接收 config 作为第一个参数,isServer 标志作为第二个参数。

注意

将来将修改 configureWebpack 的 API 以接受一个对象 (configureWebpack({config, isServer, utils, content}))

config

configureWebpack 使用根据客户端/服务器构建生成的 config 调用。您可以将其视为要与其合并的基本配置。

isServer

configureWebpack 将在服务器构建和客户端构建中都调用。服务器构建接收 true,客户端构建接收 false 作为 isServer

utils

configureWebpack 还接收一个 util 对象:

  • getStyleLoaders(isServer: boolean, cssOptions: {[key: string]: any}): Loader[]
  • getJSLoader(isServer: boolean, cacheOptions?: {}): Loader | null

您可以使用它们有条件地返回您的 webpack 配置。

例如,下面的插件修改 webpack 配置以转换 .foo 文件。

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'custom-docusaurus-plugin',
configureWebpack(config, isServer, utils) {
const {getJSLoader} = utils;
return {
module: {
rules: [
{
test: /\.foo$/,
use: [getJSLoader(isServer), 'my-custom-webpack-loader'],
},
],
},
};
},
};
}

content

configureWebpack 将使用插件加载的内容一起调用。

合并策略

我们使用 webpack-merge 将插件的 Webpack 配置部分合并到全局 Webpack 配置中。

可以指定合并策略。例如,如果您希望将 webpack 规则添加到开头而不是添加到结尾:

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'custom-docusaurus-plugin',
configureWebpack(config, isServer, utils) {
return {
mergeStrategy: {'module.rules': 'prepend'},
module: {rules: [myRuleToPrepend]},
};
},
};
}

阅读 webpack-merge 策略文档 以了解更多详细信息。

配置开发服务器

可以通过返回 devServer 字段来配置开发服务器。

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'custom-docusaurus-plugin',
configureWebpack(config, isServer, utils) {
return {
devServer: {
open: '/docs', // 打开 localhost:3000/docs 而不是 localhost:3000/
},
};
},
};
}

configurePostCss(options)

在生成客户端包期间修改 postcss-loaderpostcssOptions

应返回已修改的 postcssOptions

默认情况下,postcssOptions 如下所示:

const postcssOptions = {
ident: 'postcss',
plugins: [require('autoprefixer')],
};

示例:

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'docusaurus-plugin',
configurePostCss(postcssOptions) {
// 追加新的 PostCSS 插件。
postcssOptions.plugins.push(require('postcss-import'));
return postcssOptions;
},
};
}

postBuild(props)

在(生产)构建完成时调用。

interface Props {
siteDir: string;
generatedFilesDir: string;
siteConfig: DocusaurusConfig;
outDir: string;
baseUrl: string;
headTags: string;
preBodyTags: string;
postBodyTags: string;
routesPaths: string[];
plugins: Plugin<any>[];
content: Content;
}

示例:

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'docusaurus-plugin',
async postBuild({siteConfig = {}, routesPaths = [], outDir}) {
// 将所有渲染的路由打印到控制台。
routesPaths.map((route) => {
console.log(route);
});
},
};
}

injectHtmlTags({content})

将头部和/或主体 HTML 标签注入到 Docusaurus 生成的 HTML 中。

injectHtmlTags 将使用插件加载的内容一起调用。

function injectHtmlTags(): {
headTags?: HtmlTags;
preBodyTags?: HtmlTags;
postBodyTags?: HtmlTags;
};

type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];

type HtmlTagObject = {
/**
* HTML 标签的属性
* 例如 `{'disabled': true, 'value': 'demo', 'rel': 'preconnect'}`
*/
attributes?: {
[attributeName: string]: string | boolean;
};
/**
* 标签名称,例如 `div`、`script`、`link`、`meta`
*/
tagName: string;
/**
* 内部 HTML
*/
innerHTML?: string;
};

示例:

docusaurus-plugin/src/index.js
export default function (context, options) {
return {
name: 'docusaurus-plugin',
loadContent: async () => {
return {remoteHeadTags: await fetchHeadTagsFromAPI()};
},
injectHtmlTags({content}) {
return {
headTags: [
{
tagName: 'link',
attributes: {
rel: 'preconnect',
href: 'https://www.github.com',
},
},
...content.remoteHeadTags,
],
preBodyTags: [
{
tagName: 'script',
attributes: {
charset: 'utf-8',
src: '/noflash.js',
},
},
],
postBodyTags: [`<div> This is post body </div>`],
};
},
};
}

标签将按如下方式添加:

  • headTags 将在由配置添加的脚本之后,在闭合 </head> 标签之前插入。
  • preBodyTags 将在打开的 <body> 标签之后,在任何子元素之前插入。
  • postBodyTags 将在所有子元素之后,在闭合的 </body> 标签之前插入。

getClientModules()

返回要导入到客户端包中的 客户端模块 的路径数组。

例如,要使您的主题从用户传入的 options 中加载 customCsscustomJs 文件路径:

my-theme/src/index.js
export default function (context, options) {
const {customCss, customJs} = options || {};
return {
name: 'name-of-my-theme',
getClientModules() {
return [customCss, customJs];
},
};
}