DEV Community

Cover image for storybook + tailwind + nuxt one webpack config
florent giraud
florent giraud

Posted on

storybook + tailwind + nuxt one webpack config

At Vue Montreal we are using nuxt a lot.

Today i want to share with you something i feel it will help you as us. We wanted to add storybook to our project.

Everytime i had to create a webpack just for using storybook. And i faced a lot of bugs. And more when i wanted to use tailwind + postcss ^^.

So let's say you have a basic nuxt config with tailwind

So you should have:

  • '@nuxtjs/tailwindcss' in your buildModules
  • in your assets/css/tailwind.css
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
Enter fullscreen mode Exit fullscreen mode

And that's all.

Now you want to implement storybook.
You want to add tailwind so postcss and not creating a new webpack or at least create another full configuration...

You have to create

.storybook/main.js
.storybook/preview.js
Enter fullscreen mode Exit fullscreen mode

.storybook/preview.js

import Vue from 'vue'
import { configure } from '@storybook/vue'
import '@/assets/css/tailwind.css'

Vue.component('nuxt-link', {
  props:   ['to'],
  methods: {
    log() {
      action('link target')(this.to)
    },
  },
  template: '<a href="#" @click.prevent="log()"><slot>NuxtLink</slot></a>',
})

configure(require.context('../components', true, /\.stories\.js$/), module);
Enter fullscreen mode Exit fullscreen mode

It's basic. I Added nuxt-link for not having some bug because storybook don't know about nuxt-link.
As you see i added import '@/assets/css/tailwind.css'.

and the most impostant.

.storybook/main.js

const { getWebpackConfig } = require('nuxt')

module.exports = {
    // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.
    webpackFinal: async (sbWebpack, { configType }) => {

        const nuxtWebpack = await getWebpackConfig('client', {
            for: process.env.NODE_ENV === 'production' ? 'build' : 'dev'
        })

        const recomposedWebpackConfig = {
            mode: nuxtWebpack.mode,
            devtool: nuxtWebpack.devtool,
            entry: sbWebpack.entry,
            output: sbWebpack.output,
            bail: sbWebpack.bail,
            module: {
                rules: [
                    ...nuxtWebpack.module.rules.map(el => {
                        const reg = RegExp(el.test);
                        if (reg.test(".postcss") || reg.test(".css")) {
                            el.oneOf = el.oneOf.map(e => {
                                e.use.push({
                                    loader: 'postcss-loader',
                                    options: {
                                        ident: 'postcss',
                                        plugins: [
                                        require('tailwindcss')('./tailwind.config.js'),
                                        require('autoprefixer'),
                                        ],
                                    },
                                })
                                return e;
                            })
                        }
                        return el;
                    })
                ]
            },
            plugins: sbWebpack.plugins,
            resolve: {
                extensions: nuxtWebpack.resolve.extensions,
                modules: nuxtWebpack.resolve.modules,
                alias: {
                    ...nuxtWebpack.resolve.alias,
                    ...sbWebpack.resolve.alias,
                },
            },
            optimization: sbWebpack.optimization,
            performance: {
                ...sbWebpack.performance,
                ...nuxtWebpack.performance
            }
        }

        return recomposedWebpackConfig;
    },
};

Enter fullscreen mode Exit fullscreen mode

The 'problem' here is you need some of storybook webpack and nuxt webpack. So i decided to recompose a webpack config
with storybook custom webpack.

And THIS. A new feature from nuxt that expose nuxt webpack config with getWebpackConfig. It return a promise and it's a valid webpack export as you can export promise now too INFO HERE.

The most important part for you here is:

module: {
 rules: [
  ...nuxtWebpack.module.rules.map(el => {
    const reg = RegExp(el.test);
    if (reg.test(".postcss") || reg.test(".css")) {
      el.oneOf = el.oneOf.map(e => {
       e.use.push({
        loader: 'postcss-loader',
        options: {
         ident: 'postcss',
         plugins: [
          require('tailwindcss')('./tailwind.config.js'),
          require('autoprefixer'),
         ],
        },
      })
      return e;
     })
    }
    return el;
   })
  ]
},
Enter fullscreen mode Exit fullscreen mode

What you need to update are .postcss and .css rules.

And that's it! Now you should be able to write tailwind / postcss in your component with "ONE CONFIG" :).

This is my workaround. Maybe it's not the best so tell me in comments.

ps: An ISSUE in @nuxtjs/tailwind about adding support with storybook.

Top comments (7)

Collapse
 
manuelehrenfeld profile image
Manuel Ehrenfeld • Edited

In case this would be useful to someone else, I got it working by manually configuring the source loader:

{
test: /.(stories|story).[tj]sx?$/,
loader: require.resolve('@storybook/source-loader'),
exclude: [/node_modules/],
enforce: 'pre',
}
github.com/storybookjs/storybook/b...

Collapse
 
flozero profile image
florent giraud

do you have a repo example you can share ? I am currently having the same bug you had i think ^^. Their docs are new and not so well documented on this...

Can tell us the version you are using too? Thank's :) Because there are some bugs with next version apparently

Collapse
 
manuelehrenfeld profile image
Manuel Ehrenfeld

Hi Florent, after some issues I decided to keep two independent webpack configurations. Here you can check my implementation:
github.com/nonlinearcom/storybook-...

Thread Thread
 
flozero profile image
florent giraud

Can you describe what was your issue on it ? And thank's for the repo i will check

Collapse
 
flozero profile image
florent giraud

Hello manuel you mean this github.com/storybookjs/storybook/t... ? If yes i will try to apply those 3 addons soon to our project:

github.com/storybookjs/storybook/t...
github.com/storybookjs/storybook/t...
github.com/storybookjs/storybook/t...

You can follow me i will write an article soon about using storybook + chromatic too

Collapse
 
manuelehrenfeld profile image
Manuel Ehrenfeld

Hi Florent, great article! it solved my nuxt / postcss configuration :)
In my case, the only issue left is that there is "no code available" message under the Docs tab... do you have any idea on how to fix that?
Thanks id advance!
Manuel

Collapse
 
flozero profile image
florent giraud

thank's :).

Yeah i am facing some issues with docs too. But working on it. github.com/vuemontreal/vuemontreal....

I can work with basic doc but it's not working well with mdx