Sharing the eight-step migration experience with multiple Storybooks in a monorepo
Published in · 20 min read · May 18
--
Storybook is a tool for UI development. It makes development faster and easier by isolating components. This allows us to work on one component at a time. It streamlines UI development, testing, and documentation.
Storybook 7 was released on April 3, 2023. It is the first major release in over two years and by far the largest ever. It brings a lot of features:
- First-class Vite support
- Zero-config support for NextJS and SvelteKit powered by the new frameworks API
- Component Story Format 3 (CSF3) with improved type safety
- MDX2 support and streamlined doc blocks
- UI design refresh
- Improved interaction testing and test coverage
- Ecosystem CI for better stability and smoother upgrades
We were at Storybook 6 using React and Webpack, with three Storybooks defined in a monorepo, a software development strategy in which the code for several projects is stored in the same repository.
root
├── .storybook
│ ├── main.js
│ └── preview.jsx
├── node_modules
├── package.json
├── components
│ ├── .storybook
│ │ ├── main.js
│ │ ├── preview.jsx
│ │ └── style.css
│ └── package.json
└── apps
├── .storybook
│ ├── main.js
│ └── preview.jsx
└── package.json
- The repository has a
root
, where the globalpackage.json
is defined andnode_modules
are generated.components
is a project for common components, andapps
is a project for an enterprise application using common components via"@product/components": "link:../components"
. The packages innode_modules
are shared by bothcomponents
andapps
. - We have three Storybooks in the monorepo, the root Storybook, the component Storybook, and the app Storybook. The root Storybook is the composition of the other two Storybooks.
.storybook
is a folder for Storybook configuration.main.js
configures story file location, add-ons, as well as custom Webpack and Babel configurations.preview.js
sets the global setting for decorators, parameters, and global types.style.css
is one of the six ways to define global styles.
The task is to upgrade Storybooks to version 7. With a complicated Storybook setup, our migration is not as smooth as previous versions. We share the eight-step migration experience with you, and hopefully, it might help your applications.
Here is the summary of the steps:
- Step 1: Meet the requirements
- Step 2: Choose a migration script
- Step 3: Execute the migration script
- Step 4: Fix MDX2 Issues
- Step 5: Migrate
main.js
andpreview.js
to TypeScript - Step 6: Upgrade the component Storybook
- Step 7: Upgrade the app Storybook
- Step 8: Remove the composition Storybook
Storybook 7 requires Node 16 or above, and it no longer supports IE11. The target browser version is chrome >= 100
. It also requires Webpack 5.
Storybook 7 does not support stories that use storiesOf
. However, these stories can continue to work by setting features.storyStoreV7: false
in main.js
, with the performance penalty.
Storybook 7 does not support MDX1. It is recommended to migrate to MDX2, but MDX1 can continue to work by setting features.legacyMdx1: true
in main.js
.
Writing stories directly in MDX has been deprecated in Storybook 7. It is recommended to document stories with simple .mdx
, and write actual stories in CSF3, an improved version of CSF2 that requires writing stories with objects.
A Storybook migration script accomplishes two tasks:
- Upgrade Storybook dependencies to the latest version.
- Run a collection of automigrations, which will:
- Check for common upgrade tasks.
- Explain the necessary changes with links to more information.
- Ask for approval, and then perform the task.
There are three migration scripts provided, automigrate
, upgrade
, and prerelease
.
Automigrate Script
Here is the command to run automigrate script:
$ npx storybook@next automigrate
It runs standard configuration checks, explains what is potentially out-of-date, and offers to fix it automatically. However, it does not upgrade Storybook packages.
Upgrade script
Here is the command to run the upgrade script:
$ npx storybook@latest upgrade
It upgrades the Storybook packages to the latest stable version, performs confidence checks of package versions, and executes automigrate to check the configuration.
Prerelease script
Here is the command to run the prerelease script:
$ npx storybook@latest upgrade --prerelease
Storybook is under constant development, and prerelease versions are published almost daily. It is best to try out new features before they are generally available.
The upgrade script is the most common way to upgrade Storybook, and we use it to walk through the migration process.
At root
, execute the script:
$ npx storybook@latest upgrade
The script runs in a few steps.
Install Storybook 7 packages
The upgrade script checks for the latest versions of storybook packages and displays what needs to be upgraded:
info @storybook/addon-actions ^6.5.16 → ^7.0.11
info @storybook/addon-essentials ^6.5.16 → ^7.0.11
info @storybook/addon-links ^6.5.16 → ^7.0.11
info @storybook/addons ^6.5.16 → ^7.0.11
info @storybook/react ^6.5.16 → ^7.0.11
info @storybook/theming ^6.5.16 → ^7.0.11
info eslint-plugin-storybook ^0.6.11 → ^0.6.12
info storybook-dark-mode ^2.1.1 → ^3.0.0
It finds several outdated packages in yarn.lock
, and prints out the warning messages:
WARN Found 5 outdated packages (relative to '@storybook/addon-actions@7.0.11')
WARN Please make sure your packages are updated to ensure a consistent experience.
WARN - @storybook/core-common@6.5.16
WARN - @storybook/core-events@6.5.16
WARN - @storybook/core@6.5.16
WARN - @storybook/node-logger@6.5.16
WARN - @storybook/telemetry@6.5.16
🔎 checking possible migrations..
The devDpendencies
in package.json
are upgraded to the following:
"devDependencies": {
"@storybook/addon-actions": "^7.0.11",
"@storybook/addon-essentials": "^7.0.11",
"@storybook/addon-links": "^7.0.11",
"@storybook/addons": "^7.0.11",
"@storybook/core": "^6.5.16",
"@storybook/react": "^7.0.11",
"@storybook/theming": "^7.0.11",
"eslint-plugin-storybook": "^0.6.12",
"storybook-dark-mode": "^3.0.0"
}
Have you noticed that @storybook/core
is not upgraded? We need to handle it manually.
Install storybook binary and upgrade scripts
Storybook 6 has binaries called start-storybook
and build-storybook
. In Storybook 7, these binaries are removed and replaced by a new CLI command, storybook
. storybook dev
starts a Storybook and storybook build
builds a Storybook.
storybook
looks for the framework
field in main.js
, and use it to determine how to start or build a Storybook. The benefit of this change is that it is now possible to install multiple frameworks in a project without worrying about hoisting issues.
The upgrade script first asks whether to install the storybook
binary.
🔎 found a 'storybook-binary' migration:
╭ Automigration detected ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ We've detected you are using Storybook 7.0.11 without Storybook's storybook binary. Starting in Storybook 7.0, it has to be installed. │
│ │
│ │
│ More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#start-storybook--build-storybook-binaries-removed │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✔ Do you want to run the 'storybook-binary' migration on your project? (Y/n)
Type y
, and it runs the storybook-binary
migration.
storybook
is added to devDpendencies
in package.json
:
"devDependencies": {
"storybook": "^7.0.11"
}
Then, the upgrade script asks whether to fix Storybook scripts
in package.json
.
🔎 found a 'sb-scripts' migration:
╭ Automigration detected ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ We've detected you are using Storybook 7.0.11 with scripts from previous versions of Storybook. │
│ Starting in Storybook 7, the start-storybook and build-storybook binaries have changed to storybook dev and storybook build respectively. │
│ In order to work with Storybook 7.0.11, your storybook scripts have to be adjusted to use the binary. We can adjust them for you: │
│ │
│ build-storybook │
│ from: │
│ build-storybook │
│ to: │
│ storybook build │
│ │
│ storybook │
│ from: │
│ start-storybook -p 6006 │
│ to: │
│ storybook dev -p 6006 │
│ │
│ In case this migration did not cover all of your scripts, or you'd like more info: │
│ https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#start-storybook--build-storybook-binaries-removed │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✔ Do you want to run the 'sb-scripts' migration on your project? (Y/n)
Type y
, and it runs the sb-scripts
migration.
scripts
in package.json
are updated to use the new CLI command.
"scripts": {
"build-storybook": "storybook build",
"storybook": "storybook dev -p 6006",
}
Configure frameworks
Storybook 7 introduces the concept of frameworks, which abstracts configuration for renderers
(React, Vue, etc.), builders
(Webpack, Vite, etc.), and defaults to make integrations easier.
In Storybook 7, framework
combines a renderer
and a builder
, with the exception of a few packages that do not contain multiple builders, such as @storybook/angular
, which only has Webpack 5 support.
Here is the list of frameworks:
@storybook/angular
(same as Storybook 6)@storybook/ember
(same as Storybook 6)@storybook/html-vite
@storybook/html-webpack5
@storybook/preact-vite
@storybook/preact-webpack5
@storybook/react-vite
@storybook/react-webpack5
@storybook/nextjs
@storybook/server-webpack5
@storybook/svelte-vite
@storybook/svelte-webpack5
@storybook/sveltekit
@storybook/vue-vite
@storybook/vue-webpack5
@storybook/vue3-vite
@storybook/vue3-webpack5
@storybook/web-components-vite
@storybook/web-components-webpack5
The upgrade script asks whether to set up frameworks:
🔎 found a 'new-frameworks' migration:
╭ Automigration detected ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ We've detected your project is not fully setup with Storybook's 7 new framework format. │
│ │
│ Storybook 7 introduced the concept of frameworks, which abstracts configuration for renderers (e.g. React, Vue), builders (e.g. Webpack, Vite) and │
│ defaults to make integrations easier. │
│ │
│ Your project should be updated to use Storybook's framework: @storybook/react-webpack5. We can attempt to do this for you automatically. │
│ │
│ Here are the steps this migration will do to migrate your project: │
│ - Add the following dependencies: │
│ - * @storybook/react-webpack5 │
│ - Update or specify the framework field in .storybook/main.js with the value of "@storybook/react-webpack5". │
│ │
│ │
│ To learn more about the new framework format, see: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#new-framework-api │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
? Do you want to run the 'new-frameworks' migration on your project? › (Y/n)
Type y
, and it runs the new-frameworks
migration.
Since this is a React application, @storybook/react-webpack5
is added to devDpendencies
in package.json
:
"devDependencies": {
"@storybook/react-webpack5": "^7.0.11"
}
main.js
has been updated with the framework
field:
module.exports = {
...
framework: {
name: "@storybook/react-webpack5",
options: {}
}
};
Migrate MDX1 to MDX2
MDX allows using JSX inside markdown content. It can import components, such as interactive charts or alerts, and embed them within a markdown file. Version 2 of MDX (MDX2) was released on February 1, 2022, with better performance and improved syntax. It supports any JSX runtime, including React, Preact, Vue, Emotion, etc.
Storybook 7 uses MDX2 instead of MDX1 to write .stories.mdx
files that define and document stories. The upgrade script detects that we have 84 .stories.mdx
files, and asks whether to migrate them to MDX2:
🔎 found a 'mdx1to2' migration:
╭ Automigration detected ──────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ We've found 84 '.stories.mdx' files in your project. │
│ │
│ Storybook has upgraded to MDX2 (https://mdxjs.com/blog/v2/), which contains breaking changes from MDX1. │
│ We can try to automatically upgrade your MDX files to MDX2 format using some common patterns. │
│ │
│ After this install completes, and before you start Storybook, we strongly recommend reading the MDX2 section │
│ of the 7.0 migration guide. It contains useful tools for detecting and fixing any remaining issues. │
│ │
│ https://storybook.js.org/migration-guides/7.0 │
│ │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
? Do you want to run the 'mdx1to2' migration on your project? › (Y/n)
Type y
, and it runs the mdx1to2
migration.
Actually, for these 84 files, no changes have been made.
Configure autodocs option
Writing stories directly in MDX (.stories.mdx
files) has been deprecated in Storybook 7. It is recommended to document stories with simple .mdx
, and write stories in CSF3, an improved version of CSF2, that requires writing stories with objects.
Previously, Docs
is a tab next to Canvas
, which renders each story in docs view mode.
In Storybook7, autodocs
adds additional sidebar entries for stories.
autodocs
can be configured in main.js
, and the folder name is configurable.
module.exports = {
docs: {
autodocs: true,
defaultName: 'Docs'
}
};
autodocs
can take the following three values:
true
: It automatically creates docs for every story file.false
: It never creates docs.tag
: It only creates docs for story files with theautodocs
tag. Here is an example:
export default {
component: MyComponent,
tags: ['autodocs']
}
The upgrade script asks whether to set autodocs
to true:
🔎 found a 'autodocsTrue' migration:
╭ Automigration detected ────────────────────────────────────────────────────────────────────────────╮
│ │
│ We've changed the configuration of autodocs (previous docsPage), so now the value: │
│ - docs.autodocs: true -- means automatically create docs for every CSF file │
│ - docs.autodocs: 'tag' -- means only create autodocs for CSF files with the 'autodocs' tag │
│ - docs.autodocs: false -- means never create autodocs │
│ │
│ Based on your prior configuration, we can set the `docs.autodocs` to keep your old behaviour: │
│ │
│ docs: { autodocs: true } │
│ │
│ More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#autodocs-changes │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────╯
? Do you want to run the 'autodocsTrue' migration on your project? › (Y/n)
Type y
, and it runs the autodocsTrue
migration.
main.js
has been updated with the docs
field:
module.exports = {
...
framework: {
name: "@storybook/react-webpack5",
options: {}
},
docs: {
autodocs: true
}
};
Create root’s babel settings
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ and/or TypeScript code into a backward-compatible version of JavaScript in current and older browsers or environments. Storybook 7 now uses Babel mode v7 exclusively. By default, babelModeV7
is set to true
in main.js
. Because it is the default value, the setting is not necessary.
module.exports = {
features: {
babelModeV7: true
}
}
Storybook reads the project’s babel configuration, .babelrc.json
, babel.config.js
, etc.
The upgrade script asks whether to create a .babelrc.json
file with some basic configuration and add any necessary packages to devDependencies
.
🔎 found a 'missing-babelrc' migration:
╭ Automigration detected ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ We detected that your project does not have a babel configuration (.babelrc, babel.config.js, etc.). │
│ │
│ In version 6.x, Storybook provided its own babel settings out of the box. Now, Storybook re-uses your project's babel configuration, with small, │
│ incremental updates from Storybook addons. │
│ │
│ If your project does not have a babel configuration file, we can generate one that's equivalent to the 6.x defaults for you. Keep in mind that this can │
│ affect your project if it uses babel, and you may need to make additional changes based on your projects needs. │
│ │
│ Note: This automatic setup doesn't work in a monorepo, see the babel documentation for how to setup babel manually: │
│ https://babeljs.io/docs │
│ │
│ We can create a .babelrc.json file with some basic configuration and add any necessary package devDependencies. │
│ │
│ Please see the migration guide for more information: │
│ https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#babel-mode-v7-exclusively │
│ │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
? Do you want to run the 'missing-babelrc' migration on your project? › (Y/n)
Type y
, and it runs the missing-babelrc
migration that asks whether to add @babel/preset-env
, @babel/preset-typescript
, and @babel/preset-react
.
✔ Do you want to add the TypeScript preset? … yes
✔ Do you want to add the React preset? … yes
info Writing file to root/.babelrc.json
✔ Shall we install the required dependencies now? (@babel/preset-env, @babel/preset-typescript, @babel/preset-react) … yes
@babel/preset-env
: It is a smart preset to use the latest JavaScript without micromanaging syntax transforms.@babel/preset-typescript
: It is a recommended preset for TypeScript.@babel/preset-react
: It is a recommended preset for React. Starting from Babel mode v7,@babel/preset-react
does not include@babel/preset-flow
.
Here is the generated .babelrc.json
:
{
"sourceType": "unambiguous",
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": 100
}
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": []
}
Summary and followup
At the end, the upgrade script prints out a summary:
╭ Migration check ran successfully ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ Successful migrations: │
│ │
│ storybook-binary, sb-scripts, new-frameworks, mdx1to2, autodocsTrue, missing-babelrc │
│ │
│ ───────────────────────────────────────────────── │
│ │
│ If you'd like to run the migrations again, you can do so by running 'npx storybook@next automigrate' │
│ │
│ The automigrations try to migrate common patterns in your project, but might not contain everything needed to migrate to the latest version of │
│ Storybook. │
│ │
│ Please check the changelog and migration guide for manual migrations and more information: https://storybook.js.org/migration-guides/7.0 │
│ And reach out on Discord if you need help: https://discord.gg/storybook │
│ │
│ ───────────────────────────────────────────────── │
│ │
│ Attention: The following dependencies are duplicated which might cause unexpected behavior: │
│ │
│ @storybook/core-server: │
│ 7.0.11, 6.5.16 │
│ │
│ @storybook/core-common: │
│ 7.0.11, 6.5.16 │
│ │
│ @storybook/csf-tools: │
│ 7.0.11, 6.5.16 │
│ │
│ @storybook/node-logger: │
│ 7.0.11, 6.5.16 │
│ │
│ @storybook/telemetry: │
│ 7.0.11, 6.5.16 │
│ │
│ You can find more information for a given dependency by running yarn why <package-name> │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
This shows the scripts executed: storybook-binary
, sb-scripts
, new-frameworks
, mdx1to2
, autodocsTrue
, and missing-babelrc
.
There is a warning about @storybook 6.5.16
packages, and we need to remove @storybook/core
from devDpendencies
in package.json
.
"devDependencies": {
"@storybook/addon-actions": "^7.0.11",
"@storybook/addon-essentials": "^7.0.11",
"@storybook/addon-links": "^7.0.11",
"@storybook/addons": "^7.0.11",
"@̶s̶t̶o̶r̶y̶b̶o̶o̶k̶/c̶o̶r̶e̶":̶ "^̶6̶.5̶.1̶6̶",
"@storybook/react": "^7.0.11",
"@storybook/theming": "^7.0.11"
}
Re-execute npx storybook@latest upgrade
, and skip the mdx1to2
migration:
╭ Migration check ran successfully ───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ │
│ Skipped migrations: │
│ │
│ mdx1to2 │
│ │
│ ───────────────────────────────────────────────── │
│ │
│ If you'd like to run the migrations again, you can do so by running 'npx storybook@next automigrate' │
│ │
│ The automigrations try to migrate common patterns in your project, but might not contain everything needed to migrate to the latest version of │
│ Storybook. │
│ │
│ Please check the changelog and migration guide for manual migrations and more information: https://storybook.js.org/migration-guides/7.0 │
│ And reach out on Discord if you need help: https://discord.gg/storybook │
│ │
│ ───────────────────────────────────────────────── │
│ │
│ You can find more information for a given dependency by running yarn why <package-name> │
│ │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
The summary shows no more warnings.
Storybook 7 uses MDX2 by default for rendering Docs. MDX1 can be used with the following configuration, but it is not recommended.
module.exports = {
features: {
legacyMdx1: true
}
}
The upgrade from MDX1 to MDX2 is not fully automated due to many changes between versions. Execute the following command to detect errors:
$ npx @hipster/mdx2-issue-checker
Here are some examples of what to fix:
"Actions for {object name}" => "Actions for \{object name\}"
The number cannot exceed 7 (<7) => The number cannot exceed 7 (`<7`)
const count = 1; => export const count = 1;
There is also this warning during migration.
info => Loading presets
WARN The "@storybook/addon-mdx-gfm" addon is meant as a migration assistant for Storybook 7.0; and will likely be removed in a future version.
WARN It's recommended you read this document:
WARN https://storybook.js.org/docs/react/writing-docs/mdx#lack-of-github-flavored-markdown-gfm
WARN
WARN Once you've made the necessary changes, you can remove the addon from your package.json and storybook config.
@storybook/addon-mdx-gfm
is meant as a migration assistant for Storybook 7.0, providing Github Flavored Markdown support to Storybook docs. Once the necessary changes are made, this addon can be removed from package.json
and storybook configuration. The removal needs to be done manually.
Storybook 7 supports TypeScript for main
and preview
files. We manually migrate them to TypeScripts.
Here is root/.storybook/main.ts
:
import { StorybookConfig } from '@storybook/react-webpack5';const config: StorybookConfig = {
stories: ['./*.story.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-mdx-gfm'],
refs: {
components: {
title: 'components',
url: 'http://localhost:6007'
},
apps: {
title: 'apps',
url: 'http://localhost:6008'
}
},
framework: {
name: '@storybook/react-webpack5',
options: {fastRefresh: true}
},
docs: {
autodocs: true
}
};
Here is root/.storybook/preview.ts
:
import { Preview } from '@storybook/react';const preview: Preview = {
parameters: {
actions: {argTypesRegex: '^on[A-Z].*'},
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
};
export default preview;
At this point, we have finished the migration at root
.
With the monorepo, we have to make manual changes to the Storybook in root/components
.
It takes a few steps to make the changes.
Rename and modify main.ts
Rename root/components/.storybook/main.js
to root/components/.storybook/main.ts
. Adopt the changes in root/.storybook/main.ts
to root/components/.storybook/main.ts
.
import { StorybookConfig } from '@storybook/react-webpack5';// find stories
const stories = ...
const config: StorybookConfig = {
stories,
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'storybook-dark-mode'
],
webpackFinal: async (config) => ({
...config,
devtool: 'eval-source-map'
}),
framework: {
name: "@storybook/react-webpack5",
options: { fastRefresh: true },
},
docs: {
autodocs: true
},
features: {
storyStoreV7: false
}
};
export default config;
In the configuration above, storyStoreV7
is set to false
, as we still have legacy stories that use storiesOf
.
There are still warnings, but these stories work for the time being.
In SB7, we use the next-generation `storyStoreV7` by default, which does not support `storiesOf`.
More info, with details about how to opt-out here: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#storystorev7-enabled-by-default
Unexpected `storiesOf` usage: (line 38, col 0).
Rename and modify preview.jsx
Rename root/components/.storybook/preview.jsx
to root/components/.storybook/preview.tsx
. Adopt the changes in root/.storybook/preview.ts
to root/components/.storybook/preview.tsx
:
import * as React from 'react';
import { Preview } from '@storybook/react';
import 'antd/dist/antd.css';
import '@ant-design/compatible/assets/index.css';
import { useDarkMode } from 'storybook-dark-mode';
import ProductThemeProvider from '../src/styled/ProductThemeProvider';
import './style.css';const preview: Preview = {
parameters: {
darkMode: {
stylePreview: true,
classTarget: 'body',
darkClass: 'darkClass',
lightClass: 'lightClass',
},
actions: {argTypesRegex: '^on[A-Z].*'},
controls: {
expanded: true,
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
options: {
storySort: {
order:
[
// ordered stories
]
},
},
}
};
export default preview;
const withThemeProvider = (Story, context) => {
const [someState, useSomeState] = React.useState();
return (
<ProductThemeProvider isDarkMode={useDarkMode()} isStorybook={true} someState={someState}>
<Story {...context} useSomeState={useSomeState}/>
</ProductThemeProvider>
);
};
export const decorators = [withThemeProvider];
Upgrade scripts in root/components/package.json
Update scripts
in root/components/package.json
with the CLI command, storybook
, to start and build a Storybook.
"scripts": {
"storybook": "../../node_modules/.bin/storybook dev -p 6007",
"build-storybook": "../../node_modules/.bin/storybook build"
}
Create .babelrc.json and fix the build
We have upgraded main
, preview
, and scripts
.
Execute yarn storybook
, and it is not able to compile TypeScript:
ModuleBuildError: Module build failed (from ../../node_modules/@storybook/builder-webpack5/node_modules/babel-loader/lib/index.js):
SyntaxError: root/components/src/components/ProductComp.tsx: Unexpected token, expected "," (12:25) 10 | }
11 | `;
> 12 | const getOptions = (products: Product[]) => {
| ^
.babelrc.json
is the rescue. Copy root/.babelrc.json
to root/components/.babelrc.json
.
{
"sourceType": "unambiguous",
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": 100
}
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": []
}
The Babel configuration has resolved the TypeScript compilation issue, but it shows a new error:
ModuleNotFoundError: Module not found: Error: Can't resolve 'stream' in 'root/node_modules/csv-parse/lib/es5'BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "stream": require.resolve("stream-browserify") }'
- install 'stream-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "stream": false }
It suggests installing stream-browserify
. In fact, we have stream-browserify
installed:
$ yarn why stream-browserify
...
=> Found "stream-browserify@3.0.0"
info Reasons this module exists
- "webpack#node-libs-browser" depends on it
- Hoisted from "webpack#node-libs-browser#stream-browserify"
Let’s add stream-browserify
into the fallback configuration in main.ts
:
import { StorybookConfig } from '@storybook/react-webpack5';// find stories
const stories = ...
const config: StorybookConfig = {
stories,
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'storybook-dark-mode'
],
webpackFinal: async (config) => {
const fallback = config.resolve.fallback || {};
Object.assign(fallback, {
stream: require.resolve("stream-browserify"),
});
config.resolve.fallback = fallback;
return ({
...config,
devtool: 'eval-source-map'
})
},
framework: {
name: "@storybook/react-webpack5",
options: { fastRefresh: true },
},
docs: {
autodocs: true
},
features: {
storyStoreV7: false
}
};
export default config;
In addition, we add @types/webpack-env
, the type definition for Webpack, to devDpendencies
in package.json
to resolve further type errors that come from ../../node_modules/@storybook/builder-webpack5/node_modules/babel-loader/lib/index.js
.
"devDependencies": {
"@types/webpack-env": "^1.18.0"
}
Define types
in tsconfig.json
to include webpack-env
:
"types": ["node", "webpack-env", ...]
The build is fixed. The component Storybook starts.
╭──────────────────────────────────────────────────╮
│ │
│ Storybook 7.0.11 for react-webpack5 started │
│ 214 ms for manager and 48 s for preview │
│ │
│ Local: http://localhost:6007/ │
│ On your network: http://169.254.1.1:6007/ │
│ │
╰──────────────────────────────────────────────────╯
Fix favicon and story decorators
Go to http://localhost:6007
, and view the component Storybook:
There are two issues:
- The Storybook does not have a favicon, a small icon associated with a particular website or web page.
- The
Button
component does not have associated styles.
We create the Storybook favicon at root/public/storybook.ico
, and add root/components/.storybook/manager-head.html
to include this icon:
<link rel="shortcut icon" href="/storybook.ico">
This fixes the favicon.
We have used decorators to apply styles by decorators = [withThemeProvider]
. However, the decorators syntax has been changed in Storybook 7. Instead, decorators
becomes a field of root/components/.storybook/preview.tsx
:
const preview: Preview = {
...
decorators: [
(Story, context) => {
const [someState, useSomeState] = React.useState();
return (
<ProductThemeProvider isDarkMode={useDarkMode()} isStorybook={true} someState={someState}>
<Story {...context} useSomeState={useSomeState}/>
</ProductThemeProvider>
);
}
],
};
This fixes the Button component styling.
At root/components
, execute yarn storybook
, and it works well.
There is another issue for development. fetch-mock
, a JavaScript library to mock HTTP requests, throws an error during hot reload: fetch-mock: No fallback response defined for GET to /runtime_main.b83bdb3a8714964066e2.hot-update.json
.
This can be fixed by setting fetchMock.config.fallbackToNetwork = true
, although the setting was not needed for Storybook 6.
Because preview.tsx
sets the global setting for decorators, parameters, and global types, we add the fetchMock
setting in it:
import * as React from 'react';
import { Preview } from '@storybook/react';
import 'antd/dist/antd.css';
import '@ant-design/compatible/assets/index.css';
import { useDarkMode } from 'storybook-dark-mode';
import ProductThemeProvider from '../src/styled/ProductThemeProvider';
import './style.css';
import fetchMock from 'fetch-mock';
fetchMock.config.fallbackToNetwork = true;const preview: Preview = {
parameters: {
darkMode: {
stylePreview: true,
classTarget: 'body',
darkClass: 'darkClass',
lightClass: 'lightClass',
},
actions: {argTypesRegex: '^on[A-Z].*'},
controls: {
expanded: true,
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
options: {
storySort: {
order:
[
// ordered stories
]
},
},
},
decorators: [
(Story, context) => {
const [someState, useSomeState] = React.useState();
return (
<ProductThemeProvider isDarkMode={useDarkMode()} isStorybook={true} someState={someState}>
<Story {...context} useSomeState={useSomeState}/>
</ProductThemeProvider>
);
}
],
};
export default preview;
Now, it works well for dev mode as well.
With the monorepo, we have to make manual changes to the Storybook in root/apps
.
Similar to the component Storybook, we apply the following changes:
- Rename and modify
main.ts
+ Add the fallback configuration. - Rename and modify
preview.jsx
+ Fix Storydecorators
+ Add thefetchMock
setting. - Upgrade scripts in
root/components/package.json
. - Create
.babelrc.json
. - Fix favicon.
- Fix story decorators.
Execute yarn storybook
, and we are not able to compile TypeScript. .babelrc.json
needs to be renamed to babel.config.json
:
{
"sourceType": "unambiguous",
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": 100
}
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": []
}
What are the differences between .babelrc.json
and babel.config.json
?
.babelrc.json
is a configuration that only applies to a single part of the project.babel.config.json
is a configuration for monorepo and it compilesnode_modules
.
Our application is hosted by a monorepo. Since root/components
acts like a single repository, .babelrc.json
is still working. However, root/apps
links to common components via "@product/components": "link:../components
. It has multiple package.json
files, and babel.config.json
should be used instead, although the content is the same.
At root/apps
, execute yarn storybook
.
╭──────────────────────────────────────────────────╮
│ │
│ Storybook 7.0.11 for react-webpack5 started │
│ 306 ms for manager and 45 s for preview │
│ │
│ Local: http://localhost:6008/ │
│ On your network: http://169.254.1.1:6008/ │
│ │
╰──────────────────────────────────────────────────╯
The Storybook works, and here’s what it looks like:
Storybook composition allows us to browse components from any Storybook accessible via static URL or local URL.
Here is root/.storybook/main.ts
that we use to reference two local Storybooks:
import { StorybookConfig } from '@storybook/react-webpack5';const config: StorybookConfig = {
stories: ['./*.story.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-mdx-gfm'],
refs: {
components: {
title: 'components',
url: 'http://localhost:6007'
},
apps: {
title: 'apps',
url: 'http://localhost:6008'
}
},
framework: {
name: '@storybook/react-webpack5',
options: {fastRefresh: true}
},
docs: {
autodocs: true
}
};
It does not work with the upgraded component Storybook and app Storybook.
We have built the composited Storybook to put multiple Storybooks into a single pane. However, it requires all local Storybooks to run. It is inconvenient and resource intensive. We have decided to remove it instead of fixing it.
We have walked through the eight-step migration process on how to upgrade multiple Storybooks to version 7 in a monorepo. There are problems and solutions. Hopefully, our experience is helpful to your applications.
Thanks for reading.
Thanks, Sushmitha Aitha, S Sreeram, Rajasekhar Gandavarapu, Urian Chang, and Richard Tom for working with me on the Domino products.
Want to Connect?If you are interested, check out my directory of web development articles.
FAQs
What is the minimum node version for Storybook 7? ›
Storybook 7.0 requires Node 16 or above. If you are using an older version of Node, you will need to upgrade or keep using Storybook 6 in the meantime.
What are the framework options for Storybook 7? ›Storybook 7 introduces zero-config Vite, NextJS, and SvelteKit support. Our new Framework API configures Storybook based on your app settings, including your choice of builder (Webpack & Vite), renderer (React, Vue, Angular, Svelte, HTML), and more!
What are the new features of storybook v7? ›- 🏛️ New component-centric information architecture.
- ⬆️ Upgraded to support MDX2.
- 🧱 More powerful and consistent Doc Blocks API.
To use the Controls addon, you need to write your stories using args. Storybook will automatically generate UI controls based on your args and what it can infer about your component. Still, you can configure the controls further using argTypes, see below.
Which node version is recommended? ›Most users are advised to use the LTS version. New versions of NodeJS involve enhanced performance, the latest features, and bug fixes. The versions of NodeJS are represented with x, y, and z, where x is used to depict the significant or major changes and others are used to depict the minor changes.
Is it mandatory to have NodeJS for Playwright? ›Playwright requires Node. js version 12 or above. Run node -v from the command line to make sure you have a compatible version of Node. js.
What is the latest version of storybook? ›Storybook 7.0 - March 2023
SB7. 0 is a full rework of Storybook's core with fast build and next-generation interaction testing. ⚡️ First-class Vite support: Storybook is configured automatically based on your Vite settings, and reduced installation size & startup time.
Storybook allows developers to work on components in isolation, while Bit allows developers to version, share, and collaborate on components. Storybook allows developers to customize the development environment, while Bit allows developers to automate the process of building, testing, and deploying components.
What is the equivalent of storybook for Vue? ›With the release of Vue 3, a Storybook alternative named Histoire has gained some traction.
Is it worth it to use storybook? ›Storybook has several important use cases for developing high-quality user interfaces and building better, more scalable web applications. Here are a few: UI component development and testing: Storybook allows developers to develop and test UI components in isolation from the application's business logic and data flow.
What are the best storybook alternatives? ›
The best alternatives to Storybooks.io are Kadira, WakaTime, and CodeFactor. If these 3 options don't work for you, we've listed a few more alternatives below.
What libraries are similar to storybook? ›- Storybook. It is an open source tool for developing UI components in isolation for React, ...
- React Sketch.app. Managing the assets of design systems in Sketch is complex, error-prone and. ...
- PrimeNg. ...
- Laravel Nova. ...
- LINQPad. ...
- Laravel Voyager. ...
- Reactotron. ...
- Structor.
Radio buttons are used when a list of two or more options are mutually exclusive, meaning the user must select only one option.
What is the button component in storybook? ›Button is a clickable interactive element that triggers a response. You can place text and icons inside of a button. Buttons are often used for form submissions and to toggle elements into view.
How do I manually install storybook? ›- Step 1: Add dependencies. Add @storybook/vue. ...
- Step 2: Add an npm script. ...
- Step 3: Create the config file. ...
- Step 4: Write your stories.
Nodejs v14 can be used on Win7 but probably last version is v14.
What node versions does Playwright support? ›System requirements
Playwright requires Node. js version 10.17 or above. The browser binaries for Chromium, Firefox and WebKit work across the 3 platforms (Windows, macOS, Linux):
Storybook 6.5 supports React 18 and Angular 14 out of the box. When you run your React project for the first time, it will auto-detect the React version and use the new root API if it detects it on React 18.
What version of node does angular 13 require? ›Note: This introduction uses Angular 13, which requires Node. js version 14.15. 0 or higher.