storybook/docs/addons/writing-presets.md
2022-10-14 22:10:56 +08:00

239 lines
7.9 KiB
Markdown

---
title: 'Write a preset addon'
---
[Storybook preset addons](./addon-types.md#preset-addons) are grouped collections of `babel`, `webpack`, and `addons` configurations that support specific use cases in Storybook, such as TypeScript or MDX support.
This doc covers the [presets API](#presets-api) and how to use the presets mechanism for [advanced configuration](#advanced-configuration).
## Presets API
A preset is a set of hooks that are called by Storybook on initialization and can override configurations for `babel`, `webpack`, `addons`, and `entries`.
Each configuration has a similar signature, accepting a base configuration object and options, as in this Webpack example:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-webpack-preset-config.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
### Babel
The babel functions `babel` and `babelDefault` all configure babel in different ways.
All functions take a [Babel configuration object](https://babeljs.io/docs/en/configuration) as their argument and can modify it or return a new object.
For example, Storybook's Mihtril support uses plugins internally and here's how it configures babel:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-babel-configuration-example.ts.mdx',
]}
/>
<!-- prettier-ignore-end -->
- `babel` is applied to the preview config, after it has been initialized by storybook
- `babelDefault` is applied to the preview config before any user presets have been applied
### Webpack
The Webpack functions `webpack`, `webpackFinal`, and `managerWebpack` configure Webpack.
All functions take a [webpack4 configuration object](https://webpack.js.org/configuration/).
For example, here is how Storybook automatically adopts `create-react-app`'s configuration if it's installed, where `applyCRAWebpackConfig` is a set of smart heuristics for modifying the input config.
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-webpackfinal-example.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
- `webpack` is applied to the preview config after it has been initialized by Storybook
- `webpackFinal` is applied to the preview config after all user presets have been applied
- `managerWebpack` is applied to the manager config
As of Storybook 6.3, Storybook can run with either `webpack4` or `webpack5` builder. If your addon needs to know which version of Webpack it's running inside, the version and the actual Webpack instance itself are both available inside your preset:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-versioned-webpack.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
### Manager entries
The addon config `managerEntries` allows you to add addons to Storybook from within a preset. For addons that require custom Webpack/Babel configuration, it is easier to install the preset, and it will take care of everything.
For example, the Storysource preset contains the following code:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-storysource-manager-entries.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
This is equivalent to [registering the addon manually](../get-started/browse-stories.md#addons) in [`main.js`](../configure/overview.md#configure-story-rendering):
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-use-manager-entries.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
### Preview entries
The addon `config` function allows you to add extra preview configuration from within a preset, for example to add parameters or decorators from an addon.
For example, the Backgrounds preset contains the following code:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-backgrounds-preset-config.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
Which in turn invokes:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-backgrounds-addon-default-params.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
This is equivalent to exporting the `backgrounds` parameter manually in `main.js`.
### Addons
For users, the name `managerEntries` might be a bit too technical, so instead both users and preset-authors can simply use the `addons` property:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-register-storysource-example.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
The array of values can support both references to other presets and addons that should be included into the manager.
Storybook will automatically detect whether a reference to an addon is a preset or a manager entry by checking if the package contains a `./preset.js` or `./register.js` (manager entry), falling back to preset if it is unsure.
If this heuristic is incorrect for an addon you are using, you can explicitly opt-in to an entry being a manager entry using the `managerEntries` key.
Here's what it looks when combining presets and manager entries in the `addons` property:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-register-presets-managerentry.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
### Entries
Entries are the place to register entry points for the preview. For example, it could be used to make a basic configure-storybook preset that loads all the `*.stories.js` files into SB, instead of forcing people to copy-paste the same thing everywhere.
## Advanced Configuration
The presets API is also more powerful than the [standard configuration options](../builders/webpack.md#extending-storybooks-webpack-config) available in Storybook, so it's also possible to use presets for more advanced configuration without actually publishing a preset yourself.
For example, some users want to configure the Webpack for Storybook's UI and addons ([issue](https://github.com/storybookjs/storybook/issues/4995)), but this is not possible using [standard Webpack configuration](../builders/webpack.md#default-configuration) (it used to be possible before SB4.1). However, you can achieve this with a private preset.
If it doesn't exist yet, create a file `.storybook/main.js`:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-advanced-config-example.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
### Preview/Manager templates
It's also possible to programmatically modify the preview head/body HTML using a preset, similar to the way `preview-head.html`/`preview-body.html` can be used to [configure story rendering](../configure/story-rendering.md). The `previewHead` and `previewBody` functions accept a string, which is the existing head/body, and return a modified string.
For example, the following snippet adds a style tag to the preview head programmatically:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-preview-head.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
Similarly, the `managerHead` can be used to modify the surrounding "manager" UI, analogous to `manager-head.html`.
Finally, the preview's main page _template_ can also be overridden using the `previewMainTemplate`, which should return a reference to a file containing an `.ejs` template that gets interpolated with some environment variables. For an example, see the [Storybook's default template](https://github.com/storybookjs/storybook/blob/next/code/lib/core-common/templates/preview.ejs).
## Sharing advanced configuration
Change your `main.js` file to:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-main-import-preset-config.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
and extract the configuration to a new file `./storybook/my-preset.js`:
<!-- prettier-ignore-start -->
<CodeSnippets
paths={[
'common/storybook-preset-full-config-object.js.mdx',
]}
/>
<!-- prettier-ignore-end -->
Place your `my-preset.js` file wherever you want, if you want to share it far and wide you'll want to make it its own package.