Skip to main content
Version: 3.7.0

Swizzling

在本节中,我们将介绍如何在Docusaurus中完成布局的定制。

似曾相识...?

本节与样式和布局类似,但这次我们将自定义React组件本身,而不是它们的外观。我们将讨论Docusaurus中的一个核心概念:swizzling,它允许更深入的站点自定义

在实践中,swizzling 允许将主题组件替换为您自己的实现,并且它有两种模式:

  • Ejecting: 创建原始主题组件的副本,您可以完全自定义
  • Wrapping: 在原始主题组件周围创建一个包装器,您可以增强
Why is it called swizzling?

名称来源于Objective-C和Swift-UI: 方法交换是改变现有选择器(方法)实现的过程。

对于Docusaurus,组件交换意味着提供一个替代组件,该组件优先于主题提供的组件。

你可以将其视为React组件的猴子补丁,使你能够覆盖默认实现。Gatsby有一个类似的概念,称为主题阴影

要更深入地理解这一点,你必须了解主题组件是如何解析的

Swizzling 过程

概述

Docusaurus 提供了一个方便的交互式 CLI 来混搭组件。你通常只需要记住以下命令:

npm run swizzle

它将在你的src/theme目录中生成一个新组件,应该看起来像这个例子:

src/theme/SomeComponent.js
import React from 'react';

export default function SomeComponent(props) {
// You can fully customize this implementation
// including changing the JSX, CSS and React hooks
return (
<div className="some-class">
<h1>Some Component</h1>
<p>Some component implementation details</p>
</div>
);
}

要获取所有可用的主题和组件的概览,请运行:

npm run swizzle -- --list

使用 --help 查看所有可用的 CLI 选项,或参考 swizzle CLI 文档

Removing Unneeded Swizzled Components

如果您决定不再需要之前混入的组件,您可以简单地从src/theme目录中删除其文件。删除组件后,请确保重新启动开发服务器,以确保更改得到正确反映。

note

在交换组件后,重新启动您的开发服务器,以便Docusaurus能够识别新组件。

Prefer staying on the safe side

请务必理解哪些组件是可以安全地交换。一些组件是主题的内部实现细节

info

docusaurus swizzle 只是一个自动化的方式来帮助你替换组件。你也可以手动创建 src/theme/SomeComponent.js 文件,Docusaurus 会 解析它。这个命令背后没有内部魔法!

弹出

弹出一个主题组件的过程是创建原始主题组件的副本,您可以完全自定义和覆盖

要弹出一个主题组件,可以使用交互式的swizzle CLI,或者使用--eject选项:

npm run swizzle [theme name] [component name] -- --eject

一个例子:

npm run swizzle @docusaurus/theme-classic Footer -- --eject

这将复制当前的组件的实现到您网站的src/theme目录。Docusaurus现在将使用这个组件的副本而不是原始的那个。您现在可以完全重新实现组件。

src/theme/Footer/index.js
import React from 'react';

export default function Footer(props) {
return (
<footer>
<h1>This is my custom site footer</h1>
<p>And it is very different from the original</p>
</footer>
);
}
warning

弹出一个不安全的组件有时会导致复制大量内部代码,这些代码现在需要你自己维护。这可能会使Docusaurus的升级更加困难,因为如果接收到的属性或使用的内部主题API发生了变化,你将需要迁移你的自定义内容。

尽可能选择包装:需要维护的代码量更小。

Re-swizzling

为了在Docusaurus升级后保持弹出的组件是最新的,重新运行弹出命令并使用git diff比较更改。还建议您在文件顶部写一个简短的注释,解释您所做的更改,以便在重新弹出后更容易重新应用您的更改。

包装

包装主题组件的过程是创建一个包装器围绕原始主题组件,您可以增强它。

要包装一个主题组件,可以使用交互式的swizzle CLI,或者使用--wrap选项:

npm run swizzle [theme name] [component name] -- --wrap

一个例子:

npm run swizzle @docusaurus/theme-classic Footer -- --wrap

这将在您网站的src/theme目录中创建一个包装器。Docusaurus现在将使用组件而不是原始组件。您现在可以在原始组件周围添加自定义内容。

src/theme/Footer/index.js
import React from 'react';
import Footer from '@theme-original/Footer';

export default function FooterWrapper(props) {
return (
<>
<section>
<h2>Extra section</h2>
<p>This is an extra section that appears above the original footer</p>
</section>
<Footer {...props} />
</>
);
}
What is this @theme-original thing?

Docusaurus 使用 主题别名 来解析要使用的主题组件。新创建的包装器采用 @theme/SomeComponent 别名。@theme-original/SomeComponent 允许导入包装器所遮蔽的原始组件,而不会创建包装器导入自身的无限导入循环。

tip

包装主题是一种很好的方式,可以在不弹出的情况下在现有组件周围添加额外的组件。例如,您可以轻松地在每篇博客文章下添加自定义评论系统:

src/theme/BlogPostItem.js
import React from 'react';
import BlogPostItem from '@theme-original/BlogPostItem';
import MyCustomCommentSystem from '@site/src/MyCustomCommentSystem';

export default function BlogPostItemWrapper(props) {
return (
<>
<BlogPostItem {...props} />
<MyCustomCommentSystem />
>
);
}

什么是安全的swizzle?

能力越大,责任越大

一些主题组件是主题的内部实现细节。Docusaurus 允许你对其进行 swizzle 操作,但这可能有风险

Why is it risky?

主题作者(包括我们)可能随着时间的推移需要更新他们的主题:更改组件属性、名称、文件系统位置、类型...例如,考虑一个接收两个属性nameage的组件,但在重构后,它现在接收一个包含上述两个属性的person属性。您的组件仍然期望这两个属性,将渲染undefined

此外,内部组件可能完全消失。如果一个组件被称为Sidebar,后来被重命名为DocSidebar,您的自定义组件将被完全忽略。

标记为不安全的主题组件可能在主题次要版本之间以不兼容的方式更改。 当升级主题(或Docusaurus)时,您的自定义可能会表现异常,甚至可能破坏您的网站

对于每个主题组件,swizzle CLI 将显示主题作者声明的3种不同的安全级别

  • 安全: 此组件可以安全地进行混入,其公共API被认为是稳定的,并且在主题的主要版本中不应发生破坏性更改
  • 不安全:此组件是主题实现细节,不适合被混用,且在主题的次要版本中可能会发生破坏性更改
  • 禁止: swizzle CLI 将阻止您对这个组件进行 swizzle 操作,因为它根本没有设计为可以被 swizzle
note

某些组件可能可以安全地包装,但不能安全地弹出。

info

不要过于害怕使用不安全的组件:只需记住重大变更可能会发生,并且在次要版本升级时,您可能需要手动升级您的自定义设置。

Report your use-case

如果您有一个强烈需要使用不安全组件的用例,请在此报告,我们将共同努力找到一个使其安全的解决方案。

我应该混入哪个组件?

通常不清楚应该具体替换哪个组件才能达到预期的效果。@docusaurus/theme-classic,它提供了大部分的主题组件,大约有100个组件

tip

要打印所有@docusaurus/theme-classic组件的概述:

npm run swizzle @docusaurus/theme-classic -- --list

您可以按照以下步骤找到要调整的适当组件:

  1. 组件描述。 一些组件提供了简短的描述,这是找到合适组件的好方法。
  2. 组件名称。 官方主题组件在语义上命名,因此您应该能够从名称中推断其功能。swizzle CLI 允许您输入组件名称的一部分以缩小可用选择范围。例如,如果您运行 yarn swizzle @docusaurus/theme-classic,并输入 Doc,则只会列出与文档相关的组件。
  3. 从一个更高级别的组件开始。 组件形成一个树状结构,其中一些组件会导入其他组件。每个路由都会与一个顶级组件相关联,该路由将渲染这个组件(大多数列在内容插件中的路由中)。例如,所有博客文章页面都有@theme/BlogPostPage作为最顶层的组件。你可以从这个组件开始进行swizzle操作,然后沿着组件树向下查找,找到只渲染你目标内容的组件。找到正确的组件后,别忘了删除其他文件以取消swizzle操作,这样你就不会维护太多的组件。
  4. 阅读主题源代码并明智地使用搜索。
Just ask!

如果你仍然不知道应该替换哪个组件来实现所需的效果,你可以在我们的支持渠道中寻求帮助。

我们也希望更好地了解你最复杂的定制用例,所以请报告它们

我需要swizzle吗?

Swizzling 最终意味着你必须维护一些与 Docusaurus 内部 API 交互的额外 React 代码。如果可以,在自定义你的网站时考虑以下替代方案:

  1. 使用CSS。 CSS规则和选择器通常可以帮助您实现相当程度的自定义。有关更多详细信息,请参阅样式和布局
  2. 使用翻译。 这听起来可能令人惊讶,但翻译最终只是自定义文本标签的一种方式。例如,如果您的网站默认语言是 en,您仍然可以运行 yarn write-translations -l en 并编辑生成的 code.json。有关更多详细信息,请参阅 i18n 教程
tip

越小越好。 如果必须进行swizzling,最好只swizzle相关的部分,并尽可能少地维护自己的代码。swizzle一个小组件通常意味着在升级过程中破坏性变更的风险较小。

Wrapping 也是一个比 ejecting 更安全的选择。

使用包装你的网站

组件在 React 树的最顶部渲染,位于主题 之上,并且永远不会卸载。它是添加不应在导航过程中重新初始化的有状态逻辑(用户认证状态、购物车状态等)的理想位置。

通过手动创建文件在src/theme/Root.js来调整它:

src/theme/Root.js
import React from 'react';

// Default implementation, that you can customize
export default function Root({children}) {
return <>{children}</>;
}
tip

使用此组件来渲染React Context提供者。