How to Setup React Native Web with Storybook
Tags: reactnative, react, storybook, webdev
Published: 2020-02-25 16:42:40

*This was originally published on [codinhood.com](https://codinhood.com/micro/react-native-web-storybook)*

## TLDR

Create a file named `webpack.config.js` within the `.storybook` folder with an alias for React Native Web.

```jsx
module.exports = {
  ...
  resolve: {
    alias: {
      "react-native$": "react-native-web"
    }
  }
};
```

## Intro

[Storybook](https://storybook.js.org/) is an excellent component development environment for React and other frameworks. However, if you're using [React Native Web](https://github.com/necolas/react-native-web) or would like to create some RNW components with Storybook you'll need to add some more configuration. If you already have a React or React Native Web app setup then you might want to skip to the `Render React Native Web with Storybook` section of this article because the first section will start from scratch.

## Basic React Setup

First, initialize a `package.json`.

```jsx
npm init
```

Then, install React, Babel, Webpack, and the usual loaders for running a typical React app.

```shell
npm install react react-dom babel-loader @babel/core @babel/preset-env @babel/preset-react html-loader html-webpack-plugin webpack webpack-dev-server webpack-cli
```

### Create Webpack config

Create `webpack.config.js` at the root of the project with the following basic react configuration.

```js
const HtmlWebPackPlugin = require("html-webpack-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules\/(?!()\/).*/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
          },
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader",
          },
        ],
      },
    ],
  },
  plugins: [
    new HtmlWebPackPlugin({
      template: "./public/index.html",
      filename: "./index.html",
    }),
  ],
  devServer: {
    historyApiFallback: true,
    contentBase: "./",
    hot: true,
  },
};
```

### Public Folder and HTML

Create a `public` folder at the project root. Inside that folder, create a `index.html` with the following HTML:

```html
<!DOCTYPE html>
<html>
  <head>
    <title>React Native Web Storybook</title>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
```

### App Entry and Component

Create a folder `src` at the project root. Inside that folder, create `index.js` with the following React setup code:

```jsx
import React from "react";
import ReactDOM from "react-dom";

import App from "./App";

ReactDOM.render(<App />, document.getElementById("app"));
```

Next, create `App.js` inside the `src` folder with the following "Hello World" code

```jsx
import React from "react";

export default class App extends React.Component {
  render() {
    return <div>Hello world</div>;
  }
}
```

### Running Hello World

Add the following two scripts to the `scripts` object in `package.json` for running and building the app with Webpack.

```jsx
"scripts": {
    "build": "webpack --mode production",
    "start": "webpack-dev-server --config ./webpack.config.js --mode development",
},
```

Finally, run `npm start` in your terminal and hello world should be shown at [http://localhost:8080/](http://localhost:8080/).

![React Setup](https://codinhood.com/static/1dae5709d6070f88c4c6eab001cc57d1/7a2d1/react-setup.png)

## Setup Storybook with React

First, install Storybook.

```shell
npm i @storybook/react
```

Create a script, `storybook`, for starting the storybook dev server.

```jsx
"scripts": {
    "build": "webpack --mode production",
    "start": "webpack-dev-server --config ./webpack.config.js --mode development",
    "storybook": "start-storybook"
},
```

Create a folder, `.storybook`, at the project root. Create another project file, `main.js` within that folder and add the following:

```jsx
module.exports = {
  stories: ["../src/**/*.stories.[tj]s"],
};
```

Create `index.stories.js` within `src` to test that Storybook is configured correctly.

```jsx
import React from "react";

export default { title: "Hello World" };

export const withText = () => <div>Hello World</div>;
```

Finally, run `npm run storybook`, and the storybook server should start running on the port indicated in your terminal. In my case, the server is running on [http://localhost:57823/](http://localhost:57823/).

![Storybook setup](https://codinhood.com/static/c6d2303dc0788de56b6efd0dfd8b2453/f0628/storybook-setup.png)

## Setup React Native Web

First, install React Native Web.

```shell
npm i react-native-web
```

Go to `webpack.config.js` at the project root and add an alias for `react-native` to `react-native-web` so Webpack will pull components from `react-native-web` instead of React Native. Add the following below `plugins` and above `devServer`:

```js
...
  resolve: {
    alias: {
      "react-native$": "react-native-web",
    },
  },
  ...
```

This is the only config necessary to use React Native Web components given our current simple setup. Let's test this configuration by adding a React Native component to `src/App.js`.

```jsx
import React from "react";
import { Text } from "react-native";

export default class App extends React.Component {
  render() {
    return <Text>Hello world</Text>;
  }
}
```

Run the app server again with `npm start` and you should see "Hello World" just as before, except this time the syntax matches React Native. The main app is now set up to render React Native components.

![React native web app setup](https://codinhood.com/static/3546456dea3ea1718ebd4c4df7a008da/7cf97/react-native-web-setup.png)

## Render React Native Web with Storybook

Assuming you have React, React Native Web, and Storybook set up properly, the only step left is to add an alias for the Storybook Webpack server to look for `react-native` imports within `react-native-web`.

Create a file named `webpack.config.js` within the `.storybook` folder that resolves an alias for React Native Web as shown below.

```jsx
module.exports = {
  ...
  resolve: {
    alias: {
      "react-native$": "react-native-web"
    }
  }
};
```

Now, open `src/index.stories.js` and create a component with React Native.

```jsx
import { Text } from "react-native";
...

export const reactNative = () => <Text>React Native Web is Awesome!</Text>;

```

Run Storybook again with `npm run storybook`.

![React native web app storybook](https://codinhood.com/static/45ec54bae65161d0c408c1f79ddff4b0/f62c3/react-native-web-storybook.png)

We can use any of the API's found on React Native Web's [README](https://github.com/necolas/react-native-web#components). For example,

```jsx
import { ActivityIndicator } from "react-native";
...

export const reactNativeActivity = () => <ActivityIndicator />;

```

![React native web app activity](https://codinhood.com/static/38df67163aceb97ca0e358a88745c571/15807/react-native-web-activity.png)

## Conclusion

Getting React Native Web working with Storybook can be extremely simple, but it can also be more complicated depending on the third-party libraries your app is utilizing.