DEV Community

Cover image for Use Storybook with Laravel Jetstream, Inertia and TailwindCSS
Rachid
Rachid

Posted on

Use Storybook with Laravel Jetstream, Inertia and TailwindCSS

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 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.

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
Enter fullscreen mode Exit fullscreen mode

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:

"@storybook/manager-webpack5": "^6.4.21",
"@storybook/builder-webpack5": "^6.4.21",
Enter fullscreen mode Exit fullscreen mode

Then, we tell Storybook to use the proper builder by adding a new key in the object declared in .storybook/main.js:

"core": {
    "builder": "webpack5",
  },
Enter fullscreen mode Exit fullscreen mode

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:

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({});
Enter fullscreen mode Exit fullscreen mode

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:

"webpackFinal": async (config) => {
      config.resolve = {
          ...config.resolve,
          alias: {
              ...config.resolve?.alias,
              '@': '../resources/js',
          }
      }
      return config;
  }
Enter fullscreen mode Exit fullscreen mode

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..?

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;
  }
Enter fullscreen mode Exit fullscreen mode

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:

const path = require('path');
const tailwindcss = require('../tailwind.config');
Enter fullscreen mode Exit fullscreen mode

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

import '../resources/css/app.css';
Enter fullscreen mode Exit fullscreen mode

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

Bonus: Use Storybook on Lando

You're using Lando ? I wrote a little post to make Storybook works with Lando.

Discussion (1)

Collapse
winyardious profile image
Winyardious

Many thanks to you good sir! Ran into exactly the same issues myself plus an additional one that required me to define the version of Webpack I wanted to use in package.json after npx sb init stopped my Inertia app from running.

Found the solution to the second issue here (github.com/laravel-mix/laravel-mix...) if anyone else has the same problem.