插件
插件是构建 道格龙(Docusaurus)网站功能的基石。每个插件负责处理其自身独特的功能。插件可以独立工作,也可以作为预设(preset)的一部分捆绑分发。
创建插件
一个插件本质上是一个函数,它接受 context
和 options
这两个参数,并返回一个插件实例对象(或一个 Promise)。你可以将插件创建为函数或模块。更多信息,请参阅插件方法参考章节。
函数定义
你可以将一个插件直接作为函数包含在 道格龙(Docusaurus)的配置文件中:
export default {
// ...
plugins: [
async function myPlugin(context, options) {
// ...
return {
name: 'my-plugin',
async loadContent() {
// ...
},
async contentLoaded({content, actions}) {
// ...
},
/* 其他生命周期 API */
};
},
],
};
模块定义
你可以将一个插件作为一个模块路径,引用一个单独的文件或 npm 包:
export default {
// ...
plugins: [
// 无选项:
'./my-plugin',
// 或有选项:
['./my-plugin', options],
],
};
然后在 my-plugin
文件夹中,你可 以创建一个 index.js
文件,如下所示:
export default async function myPlugin(context, options) {
// ...
return {
name: 'my-plugin',
async loadContent() {
/* ... */
},
async contentLoaded({content, actions}) {
/* ... */
},
/* 其他生命周期 API */
};
}
你可以使用调试插件的元数据面板查看你网站中安装的所有插件。
插件有几种类型:
package
: 你安装的外部包project
: 你在项目中创建的插件,以本地文件路径的形式提供给 道格龙(Docusaurus)local
: 使用函数定义创建的插件synthetic
: 道格龙(Docusaurus)内部创建的"伪插件",这样我们就可以利用我们的模块化架构,而不需要核心做太多特殊工作。你不会在元数据中看到它,因为这是一个实现细节。
你可以通过 useDocusaurusContext().siteMetadata.pluginVersions
在客户端访问它们。
插件设计
道格龙(Docusaurus)对插件系统的实现为我们提供了一种便捷的方式来挂接到网站的生命周期中,以修改开发/构建过程中发生的事情,这包括(但不限于)扩展 webpack 配置、修改加载的数据以及创建要在页面中使用的新组件。
主题设计
当插件加载其内容后,数据通过诸如 createData
+ addRoute
或 setGlobalData
之类的操作提供给客户端。这些数据必须被序列化为纯字符串,因为插件和主题在不同的环境中运行。一旦数据到达客户端,其余部分对 React 开发者来说就变得很熟悉了:数据在组件之间传递,组件被 Webpack 打包,并通过 ReactDOM.render
渲染到窗口中……
主题提供了一套用于渲染内容的 UI 组件。 大多数内容插件需要与主题配对才能真正发挥作用。UI 是与数据模式分离的一个层,这使得更换设计变得容易。
例如,一个 道格龙(Docusaurus)博客可能由一个博客插件和一个博客主题组成。
这是一个特意构造的例子:在实践中,@docusaurus/theme-classic
为文档、博客和布局提供了主题。
export default {
themes: ['theme-blog'],
plugins: ['plugin-content-blog'],
};
如果你想使用 Bootstrap 样式,你可以用 theme-blog-bootstrap
(另一个虚构的、不存在的主题)替换掉该主题:
export default {
themes: ['theme-blog-bootstrap'],
plugins: ['plugin-content-blog'],
};
现在,虽然主题从插件接收到相同的数据,但主题选择如何将数据渲染为 UI 的方式可能会大相径庭。
虽然主题与插件共享完全相同的生命周期方法,但基于主题的设计目标,主题的实现可能与插件的实现看起来非常不同。
主题旨在完成你的 道格龙(Docusaurus)网站的构建,并提供你的网站、插件和主题本身所使用的组件。一个主题仍然像一个插件一样行事,并暴露一些生命周期方法,但它们很可能不会使用 loadContent
,因为它们只从插件接收数据,而不自己生成数据;主题通常也伴随着一个充满组件的 src/theme
目录,这些组件通过 getThemePath
生命周期方法告知核心。
总结一下:
- 主题与插件共享相同的生命周期方法
- 主题在所有现有插件之后运行
- 主题通过提供
getThemePath
来添加组件别名。