跳到主要内容
版本:2.2.0

生命周期 API

在构建过程中,插件会被并行加载,各自获取自己的内容并将它们变成路由。 插件还可以配置 webpack 或后处理构建生成的文件。

async loadContent()

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

For example, this plugin below returns a random integer between 1 to 10 as content.

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

async contentLoaded({content, actions})

loadContent 所加载的数据会在 contentLoaded 中被读取。 数据可以被渲染成路由,注册为全局数据,等等。

content

contentLoaded 会在 loadContent 完成之后被调用。 loadContent() 的返回值会被作为 content 传递给 contentLoaded

actions

actions 包含三个函数:

addRoute(config: RouteConfig): void

为网站新增一条路由。

type RouteConfig = {
path: string;
component: string;
modules?: RouteModules;
routes?: RouteConfig[];
exact?: boolean;
priority?: 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 或字符串),之后可以作为 props 提供给你的路由。 接收要存储的文件名和数据,并返回数据文件的真实路径。

比如,下面的插件会创建一个 /friends 页面,显示 你的朋友是: Yangshun, Sebastien

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

export default function FriendsComponent({friends}) {
return <div>你的朋友是:{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 prop
addRoute({
path: '/friends',
component: '@site/src/components/Friends.js',
modules: {
// 从 prop 名称 -> JSON 文件路径
friends: friendsJsonPath,
},
exact: true,
});
},
};
}

setGlobalData(data: any): void

这个函数允许创建全局插件数据,在任何页面都可以被读取,包括其他插件创建的页面以及你的主题布局。

你的主题代码可以通过 useGlobalDatausePluginData 钩子在客户端访问这一数据。

注意

全局数据是……全局的:它的体积会影响你的网站的每一页的加载时间,所以把它弄小一点。 如果可能,请选择用 createDate 创建页面专有的数据。

比如,下面的插件会创建一个 /friends 页面,显示 你的朋友是: Yangshun, Sebastien

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

export default function FriendsComponent() {
const {friends} = usePluginData('my-friends-plugin');
return <div>你的朋友是:{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;
// 生成全局朋友数据
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,由 Docusaurus 根据当前为客户端还是服务端构建生成。 你可以把它当作是会被和你的配置合并的基本配置。

isServer

configureWebpack 会在服务端构建和客户端构建时都被调用。 isServer 会在服务端构建时为 true,在客户端构建时为 false

utils

configureWebpack 也会接受一个包含了一些工具的对象:

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

你可以用它们来条件性地返回你的 webpack 配置。

例如,下面的插件修改了 webpack 配置,让它能够转译 .foo 文件。

docusaurus-plugin/src/index.js
module.exports = 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 规则被放到前面而不是后面:

docusaurus-plugin/src/index.js
module.exports = 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
module.exports = 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
module.exports = 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
module.exports = function (context, options) {
return {
name: 'docusaurus-plugin',
async postBuild({siteConfig = {}, routesPaths = [], outDir}) {
// 在控制台打印所有渲染的路径。
routesPaths.map((route) => {
console.log(route);
});
},
};
};

injectHtmlTags({content})

在 Docusaurus 生成的 HTML 中注入 head 或 body 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;
/**
* inner HTML
*/
innerHTML?: string;
};

示例:

docusaurus-plugin/src/index.js
module.exports = 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> 这是在 body 的末尾 </div>`],
};
},
};
};

getClientModules()

返回一列客户端模块的路径。这些模块会被导入进客户端包裹。

作为例子,如果你的主题会根据用户提供的 options 加载 customCsscustomJs 文件:

my-theme/src/index.js
const path = require('path');

module.exports = function (context, options) {
const {customCss, customJs} = options || {};
return {
name: 'name-of-my-theme',
getClientModules() {
return [customCss, customJs];
},
};
};