Storybook 7.0 + React.js + TailwindCSS + CSS modules + Typescript setup that #$%& works

February 21, 2023

UPDATE: when writing this I have found THIS article, that, coincidentally, was also updated around the same time.

<rant>

Setting up a storybook project should NOT be THAT hard. I mean, everyone uses Storybook, it’s the only viable option out there when working on a design system.

TailwindCSS is at the stage when it’s already gained the momentum. Even large companies are considering it. Practically EVERY front-end dev has already worked with it.

And CSS modules have beed out there for more that 6 years I believe. And even though in JavaScript terms it’s a dinosaur, a legacy, it’s very much not dead and still a top choice for many, including moi.

Not even going to say anything about Typescript and React. If you’re not using TS or never worked with TS today - you’re unemployable. And React is a standard.

Surely there should be an article somewhere on how to set all this up correctly. SURELY?!

</rant>

Well, after 4 hours of googling and trial and error, I finally was able to crack this “OH SO UNUSUAL” tech stack setup. Here is the repo, and let me highlight two points.

Point 1: Webpack 5 builder and framework

Webpack 4 is still the default choice for Storybook, but Storybook has already released support for Webpack 5, so I see no reason why we’d stick to v4. Important note here is that since we’re updating the core property, we should also update the framework

// main.ts
export default {
	framework: '@storybook/react-webpack5',
  core: {
    builder: '@storybook/builder-webpack5',
  },
}

Point 2: Don’t overwrite default Webpack rules, but add more instead

It (unfortunately!) became a habit for whatever reason, that if I need to add some custom loader, I exclude the default rule from the array and re-create it. We shouldn’t do that, because it messes up the Storybook config in a way that it becomes hard to unfuck it.

Because we need to add a PostCSS loader to our .css files, don’t try to re-create css rule with all the css-loader and style-loader etc., but just push that extra rule to the end of that array, and be done with it.

// main.ts
export default {
	...
	webpackFinal: async config => {
    config.module.rules.push({
      test: /\.css$/,
      use: [
        {
          loader: 'postcss-loader',
          options: {
            postcssOptions: {
              plugins: { tailwindcss: {}, autoprefixer: {} },
            },
          },
        },
      ],
      include: path.resolve(__dirname, '../'),
    })
    return config
  },
	...
}

That’s pretty much all I wanted to say. Those two points took me a while to understand, so hope your found my post within your first hour of searching. 😅


Telegram
I also blog about my professional life in @british_frontend (на Русском).