In the last part of this series it's finally time to use what we installed in the first two parts and use everything together!
If you have not been following along please go and have a look at the first parts in this series!
Article | Link |
---|---|
setup react native & @storybook/react-native | Step 1: Setting up React Native with Storybook |
setup react from scratch together with react native web | Step 2: Setting up react with react native web |
setup @storybook/react + react native web to run as a parallel storybook | You are here now! |
Starting point
To just do a quick recap I want to state where we are at at this point in our journey.
- After Step 1, was completed we had a running React Native project with Storybook installed. It means when we run the code we have a storybook installation, which listens to the storybook development server for react native. Further we have react-native-storyloader set up. It loads our Storybook stories files for us when we run the dev command.
- After Step 2, we have in parallel a detached vanilla React project set up, with it's own webpack configuration, which is also using react native web.
So! what do we do now?! ๐คทโโ๏ธ
Manually installing Storybook for React.js ๐คธโโ๏ธ
For our repos web alter ego React.js installation we need to install Storybook, and since this was initiated as a React Native project we need to do that manually.
It's pretty straight forward and is described well in the storybook docs here: Storybook Docs: React.js Guide. Edit: WAS well described They changes the docs....
Let's go through the steps:
1.) at the root run the command in your terminal: ๐
$ npx sb init --type react -f
-
--type react
tells the Storybook CLI to install stuff for a react project -
-f
Forces the installation, because the CLI will detect the react native installation and abort the installation without the face flag.
If everything completes properly you will see a newly created .storybook
folder in the root of you project and a .stories
folder added to your .src
folder. Further it added a couple of scripts, and @storybook/react
+ react-is
packages was installed + added to your devDependencies in your package.json
.
2.) Add our scripts to package.json
๐
It's a habit of mine to add scripts first, because it reminds me of what I'm trying to accomplish. All this work is because I want to run a script and something should happen right.
The Storybook CLI might overwrite some of the scripts already present in your package.json
, I fiddled around a bit and landed on this final version for my scripts:
"scripts": {
"android": "yarn run prestorybook && react-native run-android",
"ios": "yarn run prestorybook && react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint .",
"prestorybook": "rnstl",
"storybook": "start-storybook -p 7007",
"build-react": "webpack --mode production",
"start-react": "webpack-dev-server --config ./webpack.config.js --mode development",
"start-storybook-web": "./node_modules/@storybook/react/bin/index.js",
"build-storybook-web": "./node_modules/@storybook/react/bin/build.js",
"storybook-web": "yarn run start-storybook-web",
},
The one we are focusing on right now are the start-storybook-web
, build-storybook-web
and storybook-web
. The previous scripts we covered in the first two steps in the series.
3.) [Optional] Test our React.js Storybook installation before modifying it. ๐
At this point we already have React Native component(s) inside of src/components
and they cannot be rendered by Storybook as it is right now. To see that error in action you can right now run the script, by typing this command in your terminal:
$ yarn start-storybook-web
The error looks like this for me:
ERROR in ./node_modules/react-native-swipe-gestures/index.js 121:11
Module parse failed: Unexpected token (121:11)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
However we can try our installation on the test components the Storybook CLI added for a React.js project inside of src/stories
.
so open the file .storybook/main.js
and change the stories array
From
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
...
}
To
module.exports = {
"stories": [
"../src/stories/**/*.stories.mdx",
"../src/stories/**/*.stories.@(js|jsx|ts|tsx)"
],
...
}
and then run the script:
yarn start-storybook-web
and it should compile! Behold! ๐ฅณ
4.) Adding our React Native Stories to Storybook ๐
Close any instances and let's start adding our react native stories to our Storybook React.js setup.
Again let's modify .storybook/main.js
to load our React Native written components and *.stories.js
files.
From the above stories configuration
"stories": [
"../src/stories/**/*.stories.mdx",
"../src/stories/**/*.stories.@(js|jsx|ts|tsx)"
],
To
stories: ['../src/components/**/*.stories.[tj]s'],
Note that I removed the .mdx files, I don't use that
Again, running the yarn start-storybook-web
script will result in an error, because we have not configured the React.js Storybook installation to use React Native Web yet in a custom Webpack config.
so let's do that!
5.) Add a custom Webpack configuration to Storybook ๐
Storybook already comes with a Webpack configuration which we don't really want to modify, but rather inject our own stuff into. And since we already what we want to configure, as described in Step 2 of the series, where we got React Native Web working with React.js, we have ALMOST all the stuff we want to inject into the Storybook webpack configuration already prepared. (We are missing one alias soon to be described)
So where do we inject our stuff?
open .storybook/main.js
and at the top of the file import our webpack configuration like this:
const custom = require('../webpack.config.js');
and then in the module.exports = { ... }
add an entry called webpackFinal
like this:
const custom = require('../webpack.config')
module.exports = {
stories: ['../src/components/**/*.stories.[tj]s'],
webpackFinal: (config) => {
return {
...config,
resolve: { alias: { ...config.resolve.alias, ...custom.resolve.alias } },
module: { ...config.module, rules: custom.module.rules },
}
},
}
In this way we don't overwrite, or destroy the Webpack configuration that Storybook already comes with, but rather we inject our own alias
rules and our own module.rules
into it.
Note: yes yes I removed the addons array
Also let's not forget that we need to modify our webpack.config.js
because we want atleast more things in our aliases:
all @storybook/react-native
imports should resolve to @storybook/react
because in the React Native side we are always using the import from @storybook/react
native and obviously that's not what we want on the web side of Storybook. First the component go through React Native Web
so there is no trace left of React Native Code in them after being compiled, and then we want to run Storybook as "normal" on them.
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
template: path.resolve(__dirname, './public/index.html'),
filename: 'index.html',
inject: 'body',
})
module.exports = {
entry: path.join(__dirname, 'index.web.js'),
output: {
filename: 'bundle.js',
path: path.join(__dirname, '/build'),
},
resolve: {
alias: {
'react-native$': 'react-native-web',
'@storybook/react-native': '@storybook/react', //<-here
},
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(?!()\/).*/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
],
},
plugins: [HTMLWebpackPluginConfig],
devServer: {
historyApiFallback: true,
contentBase: './',
hot: true,
},
}
and if that is super confusing to you please read Step 2, where I try my best to explain the webpack part ๐
Let's try our yarn start-storybook-web
script again and see if it runs!
yarn start-storybook-web
๐๐๐๐๐๐ BEHOOOLD! ๐๐๐๐๐
Adding Styled components to webpack
Just for the ones of us that want's to use styled components when we create our react native components, add this line to your aliases in the webpack config and it should hook right in ๐จโ๐ป
'styled-components/native': 'styled-components',
so aliases look like this:
alias: {
'react-native$': 'react-native-web',
'@storybook/react-native': '@storybook/react',
'styled-components/native': 'styled-components',
},
Fin!
Hope this was educational and a little cool!
Now you can host a static website with your React Native components, or you can actually develop them in a browser without firing up a simulator / emulator. Which is really niiiiiiice, especially if you are running on an older machine!
See the full repo here! --> Github: react-native-storybook-boilerplate
I got it hosted on Netlify, and again, the components are all written in React Native syntax!
The other parts again!
Step | Link |
---|---|
Series: The ultimate react native ui library starter repo | Step 0 link |
Step 1: Setting up react native with Storybook | Step 1 link |
Step 2: Setting up react with react native web | Step 2 link |
Top comments (9)
Make sure to also spread your config.resolve
This wasted about a day for me.
Hey! Great articles, they are really helpful. I cannot get storybook web to detect my stories. I tried everything I found, but they refuse to apear (they work on mobile tho).
Storybook runs and gives me this error.
Couldn't find any stories in your Storybook.
Any advice?
Thanks!
Hi! I'm glad you are finding my articles helpful. It sounds to me like you are not pointing your web installation to the folder where you keep your stories
This is exactly what I have been working on and this is a great resource. I have a question, do you have any points on how to make Storybook work with
Thank you for the response!
My experience is that the more things needed to be aliased the harder it get's to scale. When it comes to styled-components it's easy to alias in the webpack configuration because they offer packages for both sides. For the web side they have their normal package
styles-components
and for react-native they havestyled-components/native
package.I have not personally used a11y in this case, and I'm not sure how you are using it. but I'm going to guess you will need to think about how it's used on both sides, web+native
I have tried this solution in our kind of old project and unfortunately for our usage it is impossible to use since react-native-web can not process components that are really native. Instead of that, you would have to mock the functionality on your own using aliases like this in webpack.config and create a mocking file, where you would mock those packages to at least simulate the functionality.
(If you had any idea to do it differently, please let me know).
There are tons of cons on this. You would have to keep your mocks updated with the packages, you have to style it perfectly the same...
We have found out that it would be too much effort and canceled it.
Anyway, thanks for walkthrough, it was worth a try and I believe that for some very simple apps, this can be useful.
Thanks for your tutorial, Part 1 and 2 was really helpful.
But when i try to run "yarn storybook-web" i get a windows script error at
"node_modules\@storybook\react\bin\index.js"
Line: 1
Char: 1
Error: Invalid character
Code: 800A03F6
Source: Microsoft JScript compilation error
couldn't find a solution for that, do you have a idea?
i solved it by installing 'cross-env' (npm i cross-env)and modifing script to be "cross-env ./node_modules/@storybook/react/bin/index.js"
Awesome walkthrough! Very helpful and it works!