Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add advanced guides #6296

Merged
merged 35 commits into from
Jan 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2a6c9f2
docs: add advanced guides
Josh-Cena Jan 8, 2022
3230389
complete
Josh-Cena Jan 9, 2022
f37d868
fix link
Josh-Cena Jan 9, 2022
2fc5f2a
Create architecture
Josh-Cena Jan 9, 2022
7661ed8
use png
Josh-Cena Jan 9, 2022
3f3b16d
explanations
Josh-Cena Jan 9, 2022
d9b624c
more text
Josh-Cena Jan 10, 2022
8bfdbaf
process.env.NODE_ENV
Josh-Cena Jan 10, 2022
c6f89d2
typo
Josh-Cena Jan 10, 2022
b037876
Add image zoom
Josh-Cena Jan 10, 2022
cb03239
nit
Josh-Cena Jan 11, 2022
eb0b594
nit
Josh-Cena Jan 11, 2022
0288031
reorganize
Josh-Cena Jan 12, 2022
12de8a7
fix links
Josh-Cena Jan 12, 2022
ef3b04d
Merge branch 'main' into jc/advanced-guides
Josh-Cena Jan 12, 2022
851b85f
fix links
Josh-Cena Jan 12, 2022
b13c78f
reorganize
Josh-Cena Jan 12, 2022
f76f130
elaborate on presets
Josh-Cena Jan 12, 2022
2408c25
fix
Josh-Cena Jan 12, 2022
14df227
Merge branch 'main' into jc/advanced-guides
Josh-Cena Jan 13, 2022
4df4dd8
routing docs
Josh-Cena Jan 13, 2022
80bf357
ssr section
Josh-Cena Jan 13, 2022
e5cd7c0
more content
Josh-Cena Jan 14, 2022
4b85a51
Merge branch 'main' into jc/advanced-guides
Josh-Cena Jan 14, 2022
cc8bf6b
complete SSR guide
Josh-Cena Jan 14, 2022
76810a8
Merge branch 'main' into jc/advanced-guides
Josh-Cena Jan 15, 2022
fe43b87
pathname://
Josh-Cena Jan 15, 2022
8ab8a28
improvements
Josh-Cena Jan 15, 2022
a2ae294
document executionenvironment
Josh-Cena Jan 17, 2022
cf4f360
Merge branch 'main' into jc/advanced-guides
Josh-Cena Jan 18, 2022
fe4e213
reformat
Josh-Cena Jan 19, 2022
26b20bf
Merge branch 'main' into jc/advanced-guides
Josh-Cena Jan 25, 2022
abf63e1
final tweaks!
Josh-Cena Jan 25, 2022
a914bf2
avoid slug
Josh-Cena Jan 25, 2022
cf3e619
oops
Josh-Cena Jan 25, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions project-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ architecting
astro
atrule
autogen
autogenerating
backport
backticks
bartosz
Expand Down Expand Up @@ -40,6 +41,7 @@ codesandbox
colocation
contravariance
corejs
crawlable
creativecommons
csvg
customizability
Expand All @@ -48,6 +50,7 @@ datagit
datas
dedup
deduplicated
déja
devto
dmitry
docgen
Expand Down Expand Up @@ -260,6 +263,7 @@ unprefixed
unswizzle
unversioned
upvotes
userland
vannicatte
vercel
vetter
Expand Down
1 change: 1 addition & 0 deletions website/_dogfooding/dogfooding.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const dogfoodingPluginInstances = [
/** @type {import('@docusaurus/types').Plugin} */
function clientModuleTestPlugin() {
return {
name: 'client-module-test-plugin',
getClientModules() {
return [
require.resolve('./clientModuleExample.ts'),
Expand Down
28 changes: 28 additions & 0 deletions website/docs/advanced/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
description: How Docusaurus works to build your app
---

# Architecture

```mdx-code-block
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Zoom from '@site/src/components/Zoom';
```

<Zoom>

![Architecture overview](/img/architecture.png)

</Zoom>

This diagram shows how Docusaurus works to build your app. Plugins each collect their content and emit JSON data; themes provide layout components which receive the JSON data as route modules. The bundler bundles all the components and emits a server bundle and a client bundle.

Although you (either plugin authors or site creators) are writing JavaScript all the time, bear in mind that the JS is actually run in different environments:

- All plugin lifecycle methods are run in Node. Therefore, until we support ES Modules in our codebase, plugin source code must be provided as CommonJS that can be `require`'d.
- The theme code is built with Webpack. They can be provided as ESM—following React conventions.

Plugin code and theme code never directly import each other: they only communicate through protocols (in our case, through JSON temp files and calls to `addRoute`). A useful mental model is to imagine that the plugins are not written in JavaScript, but in another language like Rust. The only way to interact with plugins for the user is through `docusaurus.config.js`, which itself is run in Node (hence you can use `require` and pass callbacks as plugin options).

During bundling, the config file itself is serialized and bundled, allowing the theme to access config options like `themeConfig` or `baseUrl` through [`useDocusaurusContext()`](../docusaurus-core.md#useDocusaurusContext). However, the `siteConfig` object only contains **serializable values** (values that are preserved after `JSON.stringify()`). Functions, regexes, etc. would be lost on the client side. The `themeConfig` is designed to be entirely serializable.
12 changes: 12 additions & 0 deletions website/docs/advanced/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Advanced Tutorials

This section is not going to be very structured, but we will cover the following topics:

```mdx-code-block
import DocCardList from '@theme/DocCardList';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';

<DocCardList items={useCurrentSidebarCategory().items}/>
```

We will assume that you have finished the guides, and know the basics like how to configure plugins, how to write React components, etc. These sections will have plugin authors and code contributors in mind, so we may occasionally refer to [plugin APIs](../api/plugin-methods/README.md) or other architecture details. Don't panic if you don't understand everything😉
129 changes: 129 additions & 0 deletions website/docs/advanced/plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Plugins

Plugins are the building blocks of features in a Docusaurus 2 site. Each plugin handles its own individual feature. Plugins may work and be distributed as part of a bundle via presets.

## Creating plugins {#creating-plugins}

A plugin is a function that takes two parameters: `context` and `options`. It returns a plugin instance object (or a promise). You can create plugins as functions or modules. For more information, refer to the [plugin method references section](./api/plugin-methods/README.md).

### Function definition {#function-definition}

You can use a plugin as a function directly included in the Docusaurus config file:

```js title="docusaurus.config.js"
module.exports = {
// ...
plugins: [
// highlight-start
async function myPlugin(context, options) {
// ...
return {
name: 'my-plugin',
async loadContent() {
// ...
},
async contentLoaded({content, actions}) {
// ...
},
/* other lifecycle API */
};
},
// highlight-end
],
};
```

### Module definition {#module-definition}

You can use a plugin as a module path referencing a separate file or NPM package:

```js title="docusaurus.config.js"
module.exports = {
// ...
plugins: [
// without options:
'./my-plugin',
// or with options:
['./my-plugin', options],
],
};
```

Then in the folder `my-plugin`, you can create an `index.js` such as this:

```js title="my-plugin.js"
module.exports = async function myPlugin(context, options) {
// ...
return {
name: 'my-plugin',
async loadContent() {
/* ... */
},
async contentLoaded({content, actions}) {
/* ... */
},
/* other lifecycle API */
};
};
```

---

You can view all plugins installed in your site using the [debug plugin's metadata panel](/__docusaurus/debug/metadata).

Plugins come as several types:

- `package`: an external package you installed
- `project`: a plugin you created in your project, given to Docusaurus as a local file path
- `local`: a plugin created using the function definition
- `synthetic`: a "fake plugin" Docusaurus created internally, so we take advantage of our modular architecture and don't let the core do much special work. You won't see this in the metadata because it's an implementation detail.

You can access them on the client side with `useDocusaurusContext().siteMetadata.pluginVersions`.

## Plugin 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 is not limited to) extending the webpack config, modifying the data loaded, and creating new components to be used in a page.

### Theme design

When plugins have loaded their content, the data is made available to the client side through actions like [`createData` + `addRoute`](../api/plugin-methods/lifecycle-apis.md#addRoute) or [`setGlobalData`](../api/plugin-methods/lifecycle-apis.md#setGlobalData). This data has to be _serialized_ to plain strings, because [plugins and themes run in different environments](./architecture.md). Once the data arrives on the client side, the rest becomes familiar to React developers: data is passed along components, components are bundled with Webpack, and rendered to the window through `ReactDOM.render`...

**Themes provide the set of UI components to render the content.** Most content plugins need to be paired with a theme in order to be actually useful. The UI is a separate layer from the data schema, which makes swapping designs easy.

For example, a Docusaurus blog may consist of a blog plugin and a blog theme.

:::note

This is a contrived example: in practice, `@docusaurus/theme-classic` provides the theme for docs, blog, and layouts.

:::

```js title="docusaurus.config.js"
module.exports = {
// highlight-next-line
themes: ['theme-blog'],
plugins: ['plugin-content-blog'],
};
```

And if you want to use Bootstrap styling, you can swap out the theme with `theme-blog-bootstrap` (another fictitious non-existing theme):

```js title="docusaurus.config.js"
module.exports = {
// highlight-next-line
themes: ['theme-blog-bootstrap'],
plugins: ['plugin-content-blog'],
};
```

Now, although the theme receives the same data from the plugin, how the theme chooses to _render_ the data as UI can be drastically different.

While themes share the exact same lifecycle methods with plugins, themes' implementations can look very different from those of plugins based on themes' designed objectives.

Themes are designed to complete the build of your Docusaurus site and supply the components used by your site, plugins, and the themes themselves. A theme still acts like a plugin and exposes some lifecycle methods, but most likely they would not use [`loadContent`](../api/plugin-methods/lifecycle-apis.md#loadContent), since they only receive data from plugins, but don't generate data themselves; themes are typically also accompanied by an `src/theme` directory full of components, which are made known to the core through the [`getThemePath`](../api/plugin-methods/extend-infrastructure.md#getThemePath) lifecycle.

To summarize:

- Themes share the same lifecycle methods with Plugins
- Themes are run after all existing Plugins
- Themes add component aliases by providing `getThemePath`.
Loading