生命周期 API
在构建过程中,插件会被并行加载,各自获取自己的内容并将它们变成路由。 插件还可以配置 webpack 或后处理构建生成的文件。
async loadContent()
Plugins should use this lifecycle to fetch from data sources (filesystem, remote API, headless CMS, etc.) or do some server processing. 返回值是它需要的内容。
For example, this plugin below returns a random integer between 1 to 10 as content.
module.exports = function (context, options) {
return {
name: 'docusaurus-plugin',
async loadContent() {
return 1 + Math.floor(Math.random() * 10);
},
};
};
async contentLoaded({content, actions})
The data that was loaded in loadContent
will be consumed in contentLoaded
. 数据可以被渲染成路由,注册为全局数据,等等。
content
contentLoaded
will be called after loadContent
is done. The return value of loadContent()
will be passed to contentLoaded
as content
.
actions
actions
contain three functions:
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 提供给你的路由。 接收要存储的文件名和数据,并返回数据文件的真实路径。
For example, this plugin below creates a /friends
page which displays Your friends are: Yangshun, Sebastien
:
import React from 'react';
export default function FriendsComponent({friends}) {
return <div>Your friends are {friends.join(',')}</div>;
}
export default function friendsPlugin(context, options) {
return {
name: 'docusaurus-friends-plugin',
async contentLoaded({content, actions}) {
const {createData, addRoute} = actions;
// Create friends.json
const friends = ['Yangshun', 'Sebastien'];
const friendsJsonPath = await createData(
'friends.json',
JSON.stringify(friends),
);
// Add the '/friends' routes, and ensure it receives the friends props
addRoute({
path: '/friends',
component: '@site/src/components/Friends.js',
modules: {
// propName -> JSON file path
friends: friendsJsonPath,
},
exact: true,
});
},
};
}
setGlobalData(data: any): void
这个函数允许创建全局插件数据,在任何页面都可以被读取,包括其他插件创建的页面以及你的主题布局。
This data becomes accessible to your client-side/theme code through the useGlobalData
and usePluginData
hooks.
Global data is... global: its size affects the loading time of all pages of your site, so try to keep it small. Prefer createData
and page-specific data whenever possible.
For example, this plugin below creates a /friends
page which displays Your friends are: Yangshun, Sebastien
:
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>;
}
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 配置。 If the return value is a JavaScript object, it will be merged into the final config using webpack-merge
. If it is a function, it will be called and receive config
as the first argument and an isServer
flag as the second argument.
The API of configureWebpack
will be modified in the future to accept an object (configureWebpack({config, isServer, utils, content})
)
config
configureWebpack
is called with config
generated according to client/server build. 你可以把它当作是会被和你的配置合并的基本配置。
isServer
configureWebpack
will be called both in server build and in client build. The server build receives true
and the client build receives false
as isServer
.
utils
configureWebpack
also receives an util object:
getStyleLoaders(isServer: boolean, cssOptions: {[key: string]: any}): Loader[]
getJSLoader(isServer: boolean, cacheOptions?: {}): Loader | null
你可以用它们来条件性地返回你的 webpack 配置。
For example, this plugin below modify the webpack config to transpile .foo
files.
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
will be called both with the content loaded by the plugin.
Merge strategy
We merge the Webpack configuration parts of plugins into the global Webpack config using webpack-merge.
插件可以声明合并策略。 比如,如果你希望某条 Webpack 规则被放到前面而不是后面:
module.exports = function (context, options) {
return {
name: 'custom-docusaurus-plugin',
configureWebpack(config, isServer, utils) {
return {
mergeStrategy: {'module.rules': 'prepend'},
module: {rules: [myRuleToPrepend]},
};
},
};
};
Read the webpack-merge strategy doc for more details.
Configuring dev server
The dev server can be configured through returning a devServer
field.
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)
Modifies postcssOptions
of postcss-loader
during the generation of the client bundle.
Should return the mutated postcssOptions
.
By default, postcssOptions
looks like this:
const postcssOptions = {
ident: 'postcss',
plugins: [require('autoprefixer')],
};
示例:
module.exports = function (context, options) {
return {
name: 'docusaurus-plugin',
configurePostCss(postcssOptions) {
// Appends new PostCSS plugin.
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;
}
示例:
module.exports = function (context, options) {
return {
name: 'docusaurus-plugin',
async postBuild({siteConfig = {}, routesPaths = [], outDir}) {
// Print out to console all the rendered routes.
routesPaths.map((route) => {
console.log(route);
});
},
};
};
injectHtmlTags({content})
在 Docusaurus 生成的 HTML 中注入 head 或 body HTML 标签。
injectHtmlTags
will be called both with the content loaded by the plugin.
function injectHtmlTags(): {
headTags?: HtmlTags;
preBodyTags?: HtmlTags;
postBodyTags?: HtmlTags;
};
type HtmlTags = string | HtmlTagObject | (string | HtmlTagObject)[];
type HtmlTagObject = {
/**
* Attributes of the HTML tag
* E.g. `{'disabled': true, 'value': 'demo', 'rel': 'preconnect'}`
*/
attributes?: {
[attributeName: string]: string | boolean;
};
/**
* The tag name e.g. `div`, `script`, `link`, `meta`
*/
tagName: string;
/**
* The inner HTML
*/
innerHTML?: string;
};
示例:
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> This is post body </div>`],
};
},
};
};
getClientModules()
Returns an array of paths to the client modules that are to be imported into the client bundle.
As an example, to make your theme load a customCss
or customJs
file path from options
passed in by the user:
const path = require('path');
module.exports = function (context, options) {
const {customCss, customJs} = options || {};
return {
name: 'name-of-my-theme',
getClientModules() {
return [customCss, customJs];
},
};
};