As discussed at yarnpkg/berry#592
And also at yarnpkg/berry#484
This guide is divided in 4 steps, the 3 first steps are standard, the last one is about applying the necessary fixes.
- Setup a create react app with yarn-pnp the standard way
- Install storybook the standard way
- Apply standard yarn-pnp compatibility by creating a storybook preset the standard way
- Fix Storybook packages, the hard work
Start with these versions
node --version
# v10.15.3
yarn --version
# 1.19.1
create-react-app --version
# 3.2.0
Create a react app
create-react-app yarnv2-storybook
cd yarnv2-storybook
Install yarn v2 in that folder as explained at https://next.yarnpkg.com/getting-started/install
yarn policies set-version v2
yarn --version
# 2.0.0-rc.12
We can now remove node_modules
since it is not needed anymore
rm -rf node_modules
Then install with yarn and run the react app
yarn install
yarn start
# It works as expected, nice!
Now install storybook using their slow start guide at https://storybook.js.org/docs/guides/guide-react/#manual-setup
yarn add --dev @storybook/react
yarn add react react-dom
yarn add --dev babel-loader @babel/core
Add the storybook to scripts in package.json
:
{
"scripts": {
"storybook": "start-storybook"
}
}
For a basic Storybook configuration, the only thing you need to do is tell Storybook where to find stories.
To do that, create a file at .storybook/config.js
with the following content:
import { configure } from "@storybook/react";
configure(require.context("../src", true, /\.stories\.js$/), module);
Now create a ../src/index.stories.js
file, and write your first story like this:
import React from "react";
import { Button } from "@storybook/react/demo";
export default { title: "Button" };
export const withText = () => <Button>Hello Button</Button>;
export const withEmoji = () => (
<Button>
<span role="img" aria-label="so cool">
π π π π―
</span>
</Button>
);
Now everything is ready. Run your storybook with:
yarn run storybook
# IT FAILS
By following the guide at https://storybook.js.org/docs/presets/writing-presets/#advanced-configuration
First, create a file at .storybook/yarn-preset.js
:
async function managerWebpack(config, options) {
// update config here
return config;
}
async function managerBabel(config, options) {
// update config here
return config;
}
async function webpack(config, options) {
return config;
}
async function babel(config, options) {
return config;
}
async function addons(entry = []) {
return entry;
}
module.exports = { managerWebpack, managerBabel, webpack, babel, addons };
Then, load that preset in your .storybook/presets.js
file:
const path = require("path");
module.exports = [path.resolve("./.storybook/yarn-preset")];
Add the plugin by following https://github.com/arcanis/pnp-webpack-plugin
Installation
yarn add --dev pnp-webpack-plugin
Then add it to the the preset at .storybook/yarn-preset.js
in the webpack configs (for both manager and guest config)
const PnpWebpackPlugin = require(`pnp-webpack-plugin`);
async function yarn2Config(config, options) {
const newConfig = {
...(config || {}),
resolve: {
...((config || {}).resolve || {}),
plugins: [
...(((config || {}).resolve || {}).plugins || []),
PnpWebpackPlugin
]
},
resolveLoader: {
...((config || {}).resolveLoader || {}),
plugins: [
...(((config || {}).resolveLoader || {}).plugins || []),
PnpWebpackPlugin.moduleLoader(module)
]
}
};
return newConfig;
}
module.exports = { managerWebpack: yarn2Config, webpack: yarn2Config };
Now things should work...
yarn storybook
# Fail
# Error: A package is trying to access a peer dependency that should be provided by its direct ancestor but isn't
# Required package: @babel/core (via "@babel/core")
# Required by: @babel/plugin-proposal-object-rest-spread (via /path/to/yarnv2-storybook/.yarn/virtual/@babel-plugin-proposal-object-rest-spread-virtual-a8a2f1702d/0/cache/@babel-plugin-proposal-object-rest-spread-npm-7.7.4-433eacd5f8-1.zip/node_modules/@babel/plugin-proposal-object-rest-spread/lib/index.js)
This does not sound logical at first, it loooks to me that @storybook/react
is the parent of @babel/plugin-proposal-object-rest-spread
. https://github.com/storybookjs/storybook/blob/ec8ef5c144e73ce8f762df03da0ac6c2375c223b/app/react/package.json
BUT! After checking it turns out that that @storybook/core
is the parent of @babel/plugin-proposal-object-rest-spread
, and this one does NOT list @babel/core
as a peerDependency. https://github.com/storybookjs/storybook/blob/ec8ef5c144e73ce8f762df03da0ac6c2375c223b/lib/core/package.json
So let's fix this...
After several tries (See https://github.com/crubier/yarnv2-storybook/blob/master/tries.md), @larixer 's solution did work. It is explained there yarnpkg/berry#484 (comment) . Let's apply these fixes:
Upgrade to latest unreleased atm Yarn v2 with PR #600, aka packageExtensions support (this step is optional, but convenient, the same effect can be achieved by editing lockfile instead):
yarn set version from sources
Following yarnpkg/berry#484 (comment), we add these lines to .yarnrc.yml
:
packageExtensions:
"@storybook/core@*":
peerDependencies:
"@babel/core": "*"
"@storybook/api@*":
peerDependencies:
"regenerator-runtime": "*"
"corejs-upgrade-webpack-plugin@*":
dependencies:
core-js: ^2.6.10
babel-runtime: ^6.26.0
To apply packageExtensions
, install the package again:
yarn
To ensure that node_modules
will not be transpiled via Babel, add this line to the yarn2Config
function in .storybook/yarn-preset.js
:
const jsRule = newConfig.module.rules.find(rule => rule.test.test(".js"));
jsRule.exclude = /node_modules/;
To avoid an error (See yarnpkg/berry#484 (comment)), unplug @storybook/core
:
yarn unplug @storybook/core
To prevent Storybook from failing to understand where to place babel cache. (See yarnpkg/berry#484 (comment)), create an empty node_modules
folder:
mkdir node_modules
Finally it works π! We can run:
yarn storybook
# Success