mirror of
https://github.com/facebook/docusaurus.git
synced 2025-08-03 08:49:51 +02:00
feat(v2): global data + useGlobalData + docs versions dropdown (#2971)
* doc components initial simplification
* doc components initial simplification
* add docContext test
* Add poc of global data system + use it in the theme
* Revert "doc components initial simplification"
This reverts commit f657b4c4
* revert useless changes
* avoid loosing context on docs switch
* fix docs tests
* fix @generated/globalData ts declaration / es import
* typo
* revert bad commit
* refactor navbar in multiple parts + add navbar item types validation + try to fix remaining merge bugs
* add missing watch mode for plugin debug
* fix docs global data integration, move related hooks to docs plugin + convert to TS
* change versions link label
* fix activeClassName react warning
* improve docs global data system + contextual navbar dropdown
* fix bug preventing the deployment
* refactor the global data system to namespace automatically by plugin name + plugin id
* proper NavbarItem comp
* fix tests
* fix snapshot
* extract theme config schema in separate file + rename navbar links to navbar items
* minor typos
* polish docs components/api
* polish useDocs api surface
* fix the docs version suggestions comp + data
* refactors + add docsClientUtils unit tests
* Add documentation
* typo
* Add check for duplicate plugin ids detection
* multi-instance: createData plugin data should be namespaced by plugin instance id
* remove attempt for multi-instance support
This commit is contained in:
parent
a51a56ec42
commit
15e73daae7
53 changed files with 1954 additions and 531 deletions
|
@ -7,14 +7,14 @@ title: Blog
|
|||
|
||||
To setup your site's blog, start by creating a `blog` directory.
|
||||
|
||||
Then, add a navbar link to your blog within `docusaurus.config.js`:
|
||||
Then, add a item link to your blog within `docusaurus.config.js`:
|
||||
|
||||
```js title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
// ...
|
||||
navbar: {
|
||||
links: [
|
||||
items: [
|
||||
// ...
|
||||
// highlight-next-line
|
||||
{to: 'blog', label: 'Blog', position: 'left'}, // or position: 'right'
|
||||
|
|
|
@ -220,6 +220,84 @@ function Component() {
|
|||
}
|
||||
```
|
||||
|
||||
### `useGlobalData()`
|
||||
|
||||
React hook to access Docusaurus global data created by all the plugins.
|
||||
|
||||
Global data is namespaced by plugin name, and plugin id.
|
||||
|
||||
:::info
|
||||
|
||||
Plugin id is only useful when a plugin is used multiple times on the same site. Each plugin instance is able to create its own global data.
|
||||
|
||||
:::
|
||||
|
||||
```ts
|
||||
type GlobalData = Record<
|
||||
PluginName,
|
||||
Record<
|
||||
PluginId, // "default" by default
|
||||
any // plugin-specific data
|
||||
>
|
||||
>;
|
||||
```
|
||||
|
||||
Usage example:
|
||||
|
||||
```jsx {2,5,6,7}
|
||||
import React from 'react';
|
||||
import useGlobalData from '@docusaurus/useGlobalData';
|
||||
|
||||
const MyComponent = () => {
|
||||
const globalData = useDocusaurusContext();
|
||||
const myPluginData = globalData['my-plugin']['default'];
|
||||
return <div>{myPluginData.someAttribute}</div>;
|
||||
};
|
||||
```
|
||||
|
||||
:::tip
|
||||
|
||||
Inspect your site's global data at `./docusaurus/globalData.json`
|
||||
|
||||
:::
|
||||
|
||||
### `usePluginData(pluginName: string, pluginId?: string)`
|
||||
|
||||
Access global data created by a specific plugin instance.
|
||||
|
||||
This is the most convenient hook to access plugin global data, and should be used most of the time.
|
||||
|
||||
`pluginId` is optional if you don't use multi-instance plugins.
|
||||
|
||||
Usage example:
|
||||
|
||||
```jsx {2,5,6}
|
||||
import React from 'react';
|
||||
import {usePluginData} from '@docusaurus/useGlobalData';
|
||||
|
||||
const MyComponent = () => {
|
||||
const myPluginData = usePluginData('my-plugin');
|
||||
return <div>{myPluginData.someAttribute}</div>;
|
||||
};
|
||||
```
|
||||
|
||||
### `useAllPluginInstancesData(pluginName: string)`
|
||||
|
||||
Access global data created by a specific plugin. Given a plugin name, it returns the data of all the plugins instances of that name, by pluginId.
|
||||
|
||||
Usage example:
|
||||
|
||||
```jsx {2,5,6,7}
|
||||
import React from 'react';
|
||||
import {useAllPluginInstancesData} from '@docusaurus/useGlobalData';
|
||||
|
||||
const MyComponent = () => {
|
||||
const allPluginInstancesData = useAllPluginInstancesData('my-plugin');
|
||||
const myPluginData = allPluginInstancesData['default'];
|
||||
return <div>{myPluginData.someAttribute}</div>;
|
||||
};
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
### `ExecutionEnvironment`
|
||||
|
|
|
@ -150,7 +150,7 @@ module.exports = {
|
|||
alt: 'Site Logo',
|
||||
src: 'img/logo.svg',
|
||||
},
|
||||
links: [
|
||||
items: [
|
||||
{
|
||||
to: 'docs/docusaurus.config.js',
|
||||
activeBasePath: 'docs',
|
||||
|
|
|
@ -152,10 +152,6 @@ module.exports = function (context, options) {
|
|||
|
||||
Plugins should use the data loaded in `loadContent` and construct the pages/routes that consume the loaded data (optional).
|
||||
|
||||
## `async routesLoaded(routes)`
|
||||
|
||||
Plugins can modify the routes that were generated by all plugins. `routesLoaded` is called after `contentLoaded` hook.
|
||||
|
||||
### `content`
|
||||
|
||||
`contentLoaded` will be called _after_ `loadContent` is done, the return value of `loadContent()` will be passed to `contentLoaded` as `content`.
|
||||
|
@ -191,45 +187,98 @@ type Module =
|
|||
|
||||
- `createData(name: string, data: any): Promise<string>`
|
||||
|
||||
A helper function to help you write some data (usually a string or JSON) to disk with in-built caching. It takes a file name relative to to your plugin's directory **(name)**, your data **(data)**, and will return a path to where the data is created.
|
||||
A function to help you create static data (generally json or string), that you can provide to your routes as props.
|
||||
|
||||
For example, this plugin below create a `/roll` page which display "You won xxxx" to user.
|
||||
For example, this plugin below create a `/friends` page which display `Your friends are: Yangshun, Sebastien`:
|
||||
|
||||
```jsx title="website/src/components/roll.js"
|
||||
```jsx title="website/src/components/Friends.js"
|
||||
import React from 'react';
|
||||
|
||||
export default function (props) {
|
||||
const {prizes} = props;
|
||||
const index = Math.floor(Math.random() * 3);
|
||||
return <div> You won ${prizes[index]} </div>;
|
||||
export default function FriendsComponent({friends}) {
|
||||
return <div>Your friends are {friends.join(',')}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
```javascript {4-19} title="docusaurus-plugin/src/index.js"
|
||||
module.exports = function(context, options) {
|
||||
```js {4-23} title="docusaurus-friends-plugin/src/index.js"
|
||||
export default function friendsPlugin(context, options) {
|
||||
return {
|
||||
name: 'docusaurus-plugin',
|
||||
name: 'docusaurus-friends-plugin',
|
||||
async contentLoaded({content, actions}) {
|
||||
const {createData, addRoute} = actions;
|
||||
// Create a data named 'prizes.json'.
|
||||
const prizes = JSON.stringify(['$1', 'a cybertruck', 'nothing']);
|
||||
const prizesDataPath = await createData('prizes.json', prizes);
|
||||
// Create friends.json
|
||||
const friends = ['Yangshun', 'Sebastien'];
|
||||
const friendsJsonPath = await createData(
|
||||
'friends.json',
|
||||
JSON.stringify(friends),
|
||||
);
|
||||
|
||||
// Add '/roll' page using 'website/src/component/roll.js` as the component
|
||||
// and providing 'prizes' as props.
|
||||
// Add the '/friends' routes, and ensure it receives the friends props
|
||||
addRoute({
|
||||
path: '/roll',
|
||||
component: '@site/src/components/roll.js',
|
||||
path: '/friends',
|
||||
component: '@site/src/components/Friends.js',
|
||||
modules: {
|
||||
prizes: prizesDataPath
|
||||
}
|
||||
// propName -> json file path
|
||||
friends: friendsJsonPath,
|
||||
},
|
||||
exact: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
- `setGlobalData(data: any): void`
|
||||
|
||||
This function permits to create some global plugin data, that can be read from any page, including the pages created by other plugins, and your theme layout.
|
||||
|
||||
This data become accessible to your client-side/theme code, through the [`useGlobalData`](./docusaurus-core.md#useglobaldata) and [`usePluginData`](./docusaurus-core.md#useplugindatapluginname-string-pluginid-string)
|
||||
|
||||
One this data is created, you can access it with the global data hooks APIs
|
||||
|
||||
:::caution
|
||||
|
||||
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 create a `/friends` page which display `Your friends are: Yangshun, Sebastien`:
|
||||
|
||||
```jsx title="website/src/components/Friends.js"
|
||||
import React from 'react';
|
||||
import {usePluginData} from '@docusaurus/useGlobalData';
|
||||
|
||||
export default function FriendsComponent() {
|
||||
const {friends} = usePluginData('my-friends-plugin');
|
||||
return <div>Your friends are {friends.join(',')}</div>;
|
||||
}
|
||||
```
|
||||
|
||||
```js {4-14} title="docusaurus-friends-plugin/src/index.js"
|
||||
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,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## `async routesLoaded(routes)`
|
||||
|
||||
Plugins can modify the routes that were generated by all plugins. `routesLoaded` is called after `contentLoaded` hook.
|
||||
|
||||
## `configureWebpack(config, isServer, utils)`
|
||||
|
||||
Modifies the internal webpack config. If the return value is a JavaScript object, it will be merged into the final config using [`webpack-merge`](https://github.com/survivejs/webpack-merge). If it is a function, it will be called and receive `config` as the first argument and an `isServer` flag as the argument argument.
|
||||
|
|
|
@ -295,7 +295,7 @@ module.exports = {
|
|||
alt: 'Docusaurus Logo',
|
||||
src: 'img/docusaurus.svg',
|
||||
},
|
||||
links: [
|
||||
items: [
|
||||
{to: 'docs/doc1', label: 'Getting Started', position: 'left'},
|
||||
{to: 'help', label: 'Help', position: 'left'},
|
||||
{
|
||||
|
|
|
@ -148,16 +148,18 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
### Navbar links
|
||||
### Navbar items
|
||||
|
||||
You can add links to the navbar via `themeConfig.navbar.links`:
|
||||
You can add items to the navbar via `themeConfig.navbar.items`.
|
||||
|
||||
By default, Navbar items are regular links (internal or external).
|
||||
|
||||
```js {5-15} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
links: [
|
||||
items: [
|
||||
{
|
||||
// Client-side routing, used for navigating within the website.
|
||||
// The baseUrl will be automatically prepended to this value.
|
||||
|
@ -180,7 +182,7 @@ module.exports = {
|
|||
// Custom CSS class (for styling any item).
|
||||
className: '',
|
||||
},
|
||||
// ... other links
|
||||
// ... other items
|
||||
],
|
||||
},
|
||||
// ...
|
||||
|
@ -194,14 +196,14 @@ Outbound (external) links automatically get `target="_blank" rel="noopener noref
|
|||
|
||||
### Navbar dropdown
|
||||
|
||||
Navbar items can also be dropdown items by specifying the `items`, an inner array of navbar links.
|
||||
Navbar items can also be dropdown items by specifying the `items`, an inner array of navbar items.
|
||||
|
||||
```js {9-19} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
// ...
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
links: [
|
||||
items: [
|
||||
{
|
||||
label: 'Community',
|
||||
position: 'left', // or 'right'
|
||||
|
@ -224,6 +226,46 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
### Navbar docs version dropdown
|
||||
|
||||
If you use docs with versioning, this special navbar item type that will render a dropdown with all your site's available versions. The user will be able to switch from one version to another, while staying on the same doc (as long as the doc id is constant across versions).
|
||||
|
||||
```js {5-8} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
{
|
||||
type: 'docsVersionDropdown',
|
||||
position: 'left',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Navbar docs version
|
||||
|
||||
If you use docs with versioning, this special navbar item type will link to the active/browsed version of your doc (depends on the current url), and fallback to the latest version.
|
||||
|
||||
```js {5-10} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
themeConfig: {
|
||||
navbar: {
|
||||
items: [
|
||||
{
|
||||
type: 'docsVersion',
|
||||
position: 'left',
|
||||
// to: "/path // by default, link to active/latest version
|
||||
// label: "label" // by default, show active/latest version label
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Auto-hide sticky navbar
|
||||
|
||||
You can enable this cool UI feature that automatically hides the navbar when a user starts scrolling down the page, and show it again when the user scrolls up.
|
||||
|
|
|
@ -72,6 +72,35 @@ module.exports = {
|
|||
};
|
||||
```
|
||||
|
||||
## Multi-instance plugins and plugin ids
|
||||
|
||||
It is possible to use multiple times the same plugin, on the same Docusaurus website.
|
||||
|
||||
In this case, you it is required to assign a unique id to each plugin instance.
|
||||
|
||||
By default, the plugin id is `default`.
|
||||
|
||||
```js {6,13} title="docusaurus.config.js"
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'@docusaurus/plugin-xxx',
|
||||
{
|
||||
id: 'plugin-xxx-1',
|
||||
// other options
|
||||
},
|
||||
],
|
||||
[
|
||||
'@docusaurus/plugin-xxx',
|
||||
{
|
||||
id: 'plugin-xxx-2',
|
||||
// other options
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
## Plugins design
|
||||
|
||||
Docusaurus' implementation of the plugins system provides us with a convenient way to hook into the website's lifecycle to modify what goes on during development/build, which involves (but not limited to) extending the webpack config, modifying the data being loaded and creating new components to be used in a page.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue