Use Storybook with Laravel Jetstream, Inertia and TailwindCSS
Tags: laravel, tailwindcss, inertia, storybook
Published: 2022-04-13 14:03:32

Do you want to use Storybook in your Laravel App using Jetstream and Inertia ? 
Have you met some resistance and gave up because of Webpack ?

Then this post might help you. It is the result of frustrating search over the web to make it work. Hope you'll enjoy it.

## Foreword
Before we begin, I'd like to emphasis that my knowledge in frontend is extremely limited. As Jon Stark, I know nothing Webpack-related and this post is really here to help people struggling to make Storybook work with Jetstream, Inertia and Tailwind. If you spot some horrendeous mistakes or anything that could be improved, please contact me through [Twitter](https://twitter.com/rachid_in) and I'll gladly update this post.

I wrote this post using this stack:
- Laravel v9.2
- Jetstream v2.7
- Inertia v0.11
- TailwindCSS v3
- Storybook v6.4.21

## Install Storybook
`npx sb init`
This command will snoop inside your `package.json` dependencies in order to determine which starting scripts Storybook will use. It will also install some dependencies, build a default configuration and sprinkle some default stories to begin with.

After installing it, you'll realize running Storybook will fail dramatically.
```bash
info @storybook/vue3 v6.4.21
info
info => Loading presets
info => Using implicit CSS loaders
info => Using prebuilt manager
info => Using default Webpack4 setup
ERR! TypeError: Cannot read property 'NormalModule' of undefined
```
It is using the wrong version of Webpack. Let's fix this.

## Use the proper Webpack version
Let's start by adding two dependencies that `sb init` missed while snooping our project.

In `package.json`, I'll add these two `devDependencies`:
```json
"@storybook/manager-webpack5": "^6.4.21",
"@storybook/builder-webpack5": "^6.4.21",
```

Then, we tell Storybook to use the proper builder by adding a new key in the object declared in `.storybook/main.js`:
```javascript
"core": {
    "builder": "webpack5",
  },
```

Let's run `npm install && npm run storybook` and this time, you should be able to check your brand new Storybook ! 

Now let's add a story for a Jetstream's component, let's say.. the button.

## Create a story
Remove the default stories that come by installing Storybook and inside a `stories/Button.stories.js` let's create our button's story:
```javascript
import Button from '@/Jetstream/Button.vue';

export default {
  title: 'Jetstream/Button',
  component: Button,
};

const Template = (args) => ({
  components: { Button },
  setup() {
    return { args };
  },
  template: '<Button v-bind="args">Test Button</Button>',
});

export const MyButton = Template.bind({});
```

It shouldn't work because Storybook can't resolve `'@/Jetstream/Button.vue'`.

Let's fix this.

## Fixing aliases
Inside `.storybook/main.js`, right after the `core` key we declared some steps ago, we'll add a new one called `webpackFinal` and put the aliases we have in our `webpack.mix.js`, like this:
```javascript
"webpackFinal": async (config) => {
      config.resolve = {
          ...config.resolve,
          alias: {
              ...config.resolve?.alias,
              '@': '../resources/js',
          }
      }
      return config;
  }
```

Now we can restart our Storybook with `npm run storybook` and it should be good ! 

Well.. not totally. Where is Tailwind ? 

## Importing Tailwind
We need to tell Storybook to do some fancy stuff with `postcss` because.. well I don't know and frankly I'm afraid to ask. But adding this rule to the `webpackFinal` key we added previously makes it work. It's cool right? Right..?

```javascript
config.module.rules.push({
          test: /\.css$/,
          use: [
              {
                  loader: 'postcss-loader',
                  options: {
                      postcssOptions: {
                          implementation: 'postcss',
                          plugins: {
                              tailwindcss,
                          }
                      },
                  },
              },
          ],
          include: path.resolve(__dirname, '../'),
      });
      config.resolve = {
          ...config.resolve,
          alias: {
              ...config.resolve?.alias,
              '@': '../resources/js',
          }
      }
      return config;
  }
```
I assume it is telling webpack to use postcss with a Tailwind's plugin to compile our css. Let me know if you got a better definition of what's going on here and I'll update it.

For this to work, we need to import some stuff, so at the top of the file: 
```javascript
const path = require('path');
const tailwindcss = require('../tailwind.config');
```

And we'll also import the `app.css` inside `.storybook/preview.js`:
```javascript
import '../resources/css/app.css';
```

Now we restart again Storybook et voilà! Bim! You've got your story-nertia-wind up and running.

## Final files
[Get a look at the final files here](https://gist.github.com/rachids/81ad6075f99a76acb37a9f781fbd3ee3)

## Bonus: Use Storybook on Lando
You're using Lando ? I wrote a little post to [make Storybook works with Lando](https://dev.to/rachids/use-storybook-with-lando-1e52).