生命周期API
在构建过程中,插件会并行加载以获取它们自己的内容并将其渲染到路由中。插件还可以配置webpack或对生成的文件进行后处理。
async loadContent()
插件应使用此生命周期从数据源(文件系统、远程API、无头CMS等)获取数据或进行一些服务器处理。返回值是它需要的内容。
例如,下面的插件返回一个1到10之间的随机整数作为内容。
export default 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
创建一个路由以添加到网站。
export type RouteConfig = {
/**
* With leading slash. Trailing slash will be normalized by config.
*/
path: string;
/**
* Component used to render this route, a path that the bundler can `require`.
*/
component: string;
/**
* Props. Each entry should be `[propName]: pathToPropModule` (created with
* `createData`)
*/
modules?: RouteModules;
/**
* The route context will wrap the `component`. Use `useRouteContext` to
* retrieve what's declared here. Note that all custom route context declared
* here will be namespaced under {@link RouteContext.data}.
*/
context?: RouteModules;
/**
* Nested routes config, useful for "layout routes" having subroutes.
*/
routes?: RouteConfig[];
/**
* React router config option: `exact` routes would not match subroutes.
*/
exact?: boolean;
/**
* React router config option: `strict` routes are sensitive to the presence
* of a trailing slash.
*/
strict?: boolean;
/**
* Used to sort routes.
* Higher-priority routes will be matched first.
*/
priority?: number;
/**
* Optional route metadata
*/
metadata?: RouteMetadata;
/**
* Extra props; will be available on the client side.
*/
[propName: string]: unknown;
};
/**
* Plugin authors can assign extra metadata to the created routes
* It is only available on the Node.js side, and not sent to the browser
* Optional: plugin authors are encouraged but not required to provide it
*
* Some plugins might use this data to provide additional features.
* This is the case of the sitemap plugin to provide support for "lastmod".
* See also: https://github.com/facebook/docusaurus/pull/9954
*/
export type RouteMetadata = {
/**
* The source code file path that led to the creation of the current route
* In official content plugins, this is usually a Markdown or React file
* This path is expected to be relative to the site directory
*/
sourceFilePath?: string;
/**
* The last updated date of this route
* This is generally read from the Git history of the sourceFilePath
* but can also be provided through other means (usually front matter)
*
* This has notably been introduced for adding "lastmod" support to the
* sitemap plugin, see 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
一个声明式回调,用于创建静态数据(通常是JSON或字符串),这些数据稍后可以作为props提供给您的路由。接收文件名和要存储的数据,并返回实际数据文件的路径。
例如,下面的插件创建了一个/friends页面,显示你的朋友是: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
此函数允许创建一些全局插件数据,这些数据可以从任何页面读取,包括由其他插件创建的页面以及您的主题布局。
这些数据可以通过useGlobalData和usePluginData钩子访问到你的客户端/主题代码中。
全局数据是...全局的:它的大小会影响您网站所有页面的加载时间,因此请尽量保持其较小。尽可能优先使用createData和页面特定数据。
例如,下面的插件创建了一个/friends页面,显示你的朋友是: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;
// Create friends global data
setGlobalData({friends: ['Yangshun', 'Sebastien']});
// Add the '/friends' routes
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 还接收一个实用工具对象:
getStyleLoaders(isServer: boolean, cssOptions: {[key: string]: any}): Loader[]getJSLoader(isServer: boolean, cacheOptions?: {}): Loader | null
您可以使用它们有条件地返回您的webpack配置。
例如,下面的插件修改了webpack配置以转译.foo文件。
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规则被前置而不是追加:
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字段来配置。
export default function (context, options) {
return {
name: 'custom-docusaurus-plugin',
configureWebpack(config, isServer, utils) {
return {
devServer: {
open: '/docs', // Opens localhost:3000/docs instead of localhost:3000/
},
};
},
};
}
configurePostCss(options)
在生成客户端包期间修改postcss-loader的postcssOptions。
应该返回修改后的 postcssOptions。
默认情况下,postcssOptions 看起来像这样:
const postcssOptions = {
ident: 'postcss',
plugins: [require('autoprefixer')],
};
示例:
export default 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;
}
示例:
export default 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})
将头部和/或身体HTML标签注入到Docusaurus生成的HTML中。
injectHtmlTags 将在插件加载内容时被调用。
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;
};
示例:
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将在由配置添加的脚本之后插入到关闭的标签之前。preBodyTags将在打开标签后插入,在任何子元素之前。postBodyTags将在所有子元素之后插入到关闭的标签之前。
getClientModules()
返回一个路径数组,这些路径指向要导入到客户端包中的客户端模块。
例如,为了让你的主题从用户传入的options中加载customCss或customJs文件路径:
export default function (context, options) {
const {customCss, customJs} = options || {};
return {
name: 'name-of-my-theme',
getClientModules() {
return [customCss, customJs];
},
};
}