storybook + tailwind + nuxt one webpack config
florent giraud
Posted on May 3, 2020
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';
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
.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);
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;
},
};
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;
})
]
},
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.
Posted on May 3, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.