docs(v2): add doc for wrapping theme components with @theme-original and @theme-init (#3502)

* add doc for wrapping theme components

* fix tests

* Minor improvements

Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>
This commit is contained in:
Sébastien Lorber 2020-09-30 18:15:47 +02:00 committed by GitHub
parent 9cbca49ecf
commit dc31dad1de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 8 deletions

View file

@ -83,8 +83,6 @@ What this means to the user is that if you wish to use the `CompLibrary` module,
If you wish to use your own components inside the website directory, use `process.cwd()` which will refer to the `website` directory to construct require paths. For example, if you add a component to `website/core/mycomponent.js`, you can use the require path, `'process.cwd() + /core/mycomponent.js'`.
There is a special import for custom items `@theme-original`. The `theme-original` alias (just like using `theme` alias) will not get the theme component from the plugin's code. While the `init-theme` alias refers to the proper (theme) component (from the theme itself, where it is first defined). Therefore the `theme-original` is for the user and `theme-initial` is for the plugins.
## Provided Components
Docusaurus provides the following components in `CompLibrary`:

View file

@ -13,7 +13,7 @@ describe('themeAlias', () => {
test('valid themePath 1 with components', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, 'theme-1');
const alias = themeAlias(themePath);
const alias = themeAlias(themePath, true);
expect(alias).toEqual({
'@theme/Footer': path.join(themePath, 'Footer/index.js'),
'@theme-original/Footer': path.join(themePath, 'Footer/index.js'),
@ -37,7 +37,7 @@ describe('themeAlias', () => {
test('valid themePath 2 with components', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, 'theme-2');
const alias = themeAlias(themePath);
const alias = themeAlias(themePath, true);
expect(alias).toEqual({
'@theme/Navbar': path.join(themePath, 'Navbar.js'),
'@theme-original/Navbar': path.join(themePath, 'Navbar.js'),
@ -62,7 +62,7 @@ describe('themeAlias', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, 'empty-theme');
fs.ensureDirSync(themePath);
const alias = themeAlias(themePath);
const alias = themeAlias(themePath, true);
expect(alias).toEqual({});
});
@ -77,7 +77,7 @@ describe('themeAlias', () => {
test('invalid themePath that does not exist', () => {
const fixtures = path.join(__dirname, '__fixtures__');
const themePath = path.join(fixtures, '__noExist__');
const alias = themeAlias(themePath);
const alias = themeAlias(themePath, true);
expect(alias).toEqual({});
});
});

View file

@ -13,7 +13,7 @@ import {ThemeAlias} from '@docusaurus/types';
export default function themeAlias(
themePath: string,
addOriginalAlias: boolean = true,
addOriginalAlias: boolean,
): ThemeAlias {
if (!fs.pathExistsSync(themePath)) {
return {};

View file

@ -31,7 +31,7 @@ export default function loadThemeAlias(
let aliases = {};
themePaths.forEach((themePath) => {
const themeAliases = themeAlias(themePath);
const themeAliases = themeAlias(themePath, true);
aliases = {...aliases, ...buildThemeAliases(themeAliases, aliases)};
});

View file

@ -101,6 +101,58 @@ npm run swizzle @docusaurus/theme-classic
**Note**: You need to restart your webpack dev server in order for Docusaurus to know about the new component.
## Wrapping theme components
Sometimes, you just want to wrap an existing theme component with additional logic, and it can be a pain to have to maintain an almost duplicate copy of the original theme component.
In such case, you should swizzle the component you want to wrap, but import the original theme component in your customized version to wrap it.
### For site owners
The `@theme-original` alias allows you to import the original theme component.
Here is an example to display some text just above the footer, with minimal code duplication.
```js title="src/theme/Footer.js"
// Note: importing from "@theme/Footer" would fail due to the file importing itself
import OriginalFooter from '@theme-original/Footer';
export default function Footer(props) {
return (
<>
<div>Before footer</div>
<OriginalFooter {...props} />
</>
);
}
```
### For plugin authors
One theme can wrap a component from another theme, by importing the component from the initial theme, using the `@theme-init` import.
Here's an example of using this feature to enhance the default theme `CodeBlock` component with a `react-live` playground feature.
```js
import InitialCodeBlock from '@theme-init/CodeBlock';
export default function CodeBlock(props) {
return props.live ? (
<ReactLivePlayground {...props} />
) : (
<InitialCodeBlock {...props} />
);
}
```
Check the code of `docusaurus-theme-live-codeblock` for details.
:::caution
Unless you want publish to npm a "theme enhancer" (like `docusaurus-theme-live-codeblock`), you likely don't need `@theme-init`.
:::
## Official themes by Docusaurus
### `@docusaurus/theme-classic`