In addition to the Storybook for React setup, you'll also need to install these packages:
npm i -D @babel/core babel-loader css-loader style-loader
In addition to the Storybook for React setup, you'll also need to install these packages:
npm i -D @babel/core babel-loader css-loader style-loader
const path = require('path'); | |
module.exports = { | |
stories: ['../stories/**/*.stories.js', '../stories/**/*.stories.tsx'], | |
addons: ['@storybook/addon-actions', '@storybook/addon-links'], | |
presets: [path.resolve(__dirname, './next-preset.js')] | |
}; |
const path = require('path'); | |
module.exports = { | |
webpackFinal: async (baseConfig, options) => { | |
// Modify or replace config. Mutating the original reference object can cause unexpected bugs. | |
const { module = {} } = baseConfig; | |
const newConfig = { | |
...baseConfig, | |
module: { | |
...module, | |
rules: [...(module.rules || [])] | |
} | |
}; | |
// TypeScript with Next.js | |
newConfig.module.rules.push({ | |
test: /\.(ts|tsx)$/, | |
include: [ | |
path.resolve(__dirname, '../components'), | |
path.resolve(__dirname, '../stories') | |
], | |
use: [ | |
{ | |
loader: 'babel-loader', | |
options: { | |
presets: ['next/babel'], | |
plugins: ['react-docgen'] | |
} | |
} | |
] | |
}); | |
newConfig.resolve.extensions.push('.ts', '.tsx'); | |
// | |
// CSS Modules | |
// Many thanks to https://github.com/storybookjs/storybook/issues/6055#issuecomment-521046352 | |
// | |
// First we prevent webpack from using Storybook CSS rules to process CSS modules | |
newConfig.module.rules.find( | |
rule => rule.test.toString() === '/\\.css$/' | |
).exclude = /\.module\.css$/; | |
// Then we tell webpack what to do with CSS modules | |
newConfig.module.rules.push({ | |
test: /\.module\.css$/, | |
include: path.resolve(__dirname, '../components'), | |
use: [ | |
'style-loader', | |
{ | |
loader: 'css-loader', | |
options: { | |
importLoaders: 1, | |
modules: true | |
} | |
} | |
] | |
}); | |
return newConfig; | |
} | |
}; |
// If you need global CSS, you can import it here and Storybook will automatically include it in all stories. | |
// You don't need this if you don't have any global CSS. | |
import '../src/styles.css'; |
Thanks @justincy!
I'm experiencing some issues with Storybook not applying directives (e.g., @apply
) correctly, however, it works with NextJS.
Do you have any ideas about this, and do they work for you?
@andymeek I don't use @apply
. Are you using Tailwind? I got that working once with @apply
by including postcss-loader
.
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
modules: true
}
}, 'postcss-loader'
]
I managed to get SCSS modules working with
@storybook/preset-scss
:{ name: '@storybook/preset-scss', options: { cssLoaderOptions: { modules: { auto: true } } } },Global style import also works in
preview.js
.https://github.com/storybookjs/presets/tree/master/packages/preset-scss
EDIT: I added the
auto
option to css modules to prevent classes in my global files to be scoped.
This worked for me too! thanks @drskullster
Below is the config I used to get css-modules to work with tailwind + scss + anything you put in postcss- the same as in the SPA via Next.js v10.
Note that I manually installed all of the below packages since I've had some PostCss warnings which indicated I am not passing in any config, which made me suspect PostCss7 was used somewhere below. If you experience the lack of tailwind styling in storybook- that's probably it.
Also note that sass-loader comes last in the loader array.
const removeIndex = newConfig.module.rules.findIndex(
(rule) => rule.test.toString() === "/\\.css$/"
);
if (removeIndex !== -1) {
newConfig.module.rules.splice(removeIndex, 1);
}
newConfig.module.rules.push({
test: /\.(s*)css$/,
loaders: [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: { auto: true },
},
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
config: path.resolve(__dirname, "..", "postcss.config.js"),
},
},
},
"sass-loader",
],
});
This is my package.json:
"devDependencies": {
"@storybook/react": "6.1.11",
"css-loader": "5.0.1",
"postcss": "8.2.1",
"postcss-flexbugs-fixes": "5.0.2",
"postcss-import": "14.0.0",
"postcss-loader": "4.1.0",
"postcss-preset-env": "6.7.0",
"sass": "1.30.0",
"sass-loader": "10.1.0",
"style-loader": "2.0.0"
}
As a result, I was able to use both tailwind and scss syntax in my css modules:
.disabled {
@apply hover:shadow-none;
@extend .non-interactive;
}
Make sure you import your global css files in preview.js, the same way your _app
component would.
Thanks @justincy
A config for NextJS Absolute Imports and Module path aliases
somewhere convenient in next-preset.js
baseConfig.resolve.alias = {
...baseConfig.resolve.alias,
"@/components": path.resolve(__dirname, "../components"),
};
Thanks @justincy
What a fun time figuring this out. thanks everyone above for the information 🙏 🙇.
Unfortunately none of yall's solutions seemed to work for my setup, but they gave me the direction to figure it out 😄
Here are relevant pieces to my setup. Most notably typescript, nextjs, tailwind, postcss, sass, css modules
"dependencies": {
"next": "10.1.2",
"react": "17.0.2",
"tailwindcss": "^2.0.4"
},
"devDependencies": {
"@storybook/react": "^6.2.0",
"css-loader": "^3.6.0",
"postcss": "^8.2.9",
"postcss-loader": "^4.2.0",
"sass": "^1.32.6",
"sass-loader": "^10.1.1",
"style-loader": "^1.3.0",
"typescript": "^4.2.3",
}
// .storybook/main.js
const path = require("path");
module.exports = {
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-links",
"@storybook/addon-essentials",
],
webpackFinal: async (config) => {
config.module.rules.push({
test: /\.(sc|sa|c)ss$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
importLoaders: 1,
modules: {
auto: true,
},
},
},
{
loader: "postcss-loader",
options: {
// it "compiles" when I omit these options but I didn't confirm whether the correct postcss
// version is imported when omiting this.. So having it here helps me sleep at night
implementation: require("postcss"),
postcssOptions: {
config: path.resolve(__dirname, "..", "postcss.config.js"),
},
},
},
"sass-loader",
],
include: path.resolve(__dirname, "..", "src"),
});
return config;
},
};
Key reasons why the above worked:
{ modules: { auto: true } }
is magical.
/\.module(s)?\.\w+$/i
which allows you to use same rule for regular css files (css files that are not imported as modules into jsx/tsx) and not have to manually exclude .module.scss files (as others have done above 👆)test: /\.(sc|sa|c)ss$/
include: path.resolve(__dirname, "..", "src"),
.css
imports get processed and break for w/e reason 🤷♂️style-loader
-> css-loader
-> postcss-loader
-> sass-loader
And here are things that DID NOT work and my (possibly incorrect) understanding on why...
@storybook/addon-postcss
I added it because I got a deprecation warning that relying on implicit PostCSS loader is deprecated, but b/c I'm manually including the postcss-loader
for .css
files I don't think it's necessary and is just a distraction and not really doing anything.
@storybook/preset-scss
This was the most frustrating false hope. It's ONLY useful if you don't need to process s[ca]ss files with postcss. But because I'm using tailwindcss (which relies on postcss) it's completely useless. See why, here.
P.S. what was crucial to debugging this was printing the webpack storybook is using, via:
npm run storybook -- --debug-webpack
Cheers!
@joebartels - Thank you! - This is the only config I could get to work with SB v6.4, next 11, and SCSS.
@justincy Thank you for your guide!
I made a minimal example using Next.js(v11) + Storybook(v6.3) + CSS Modules.
It works with .module.css
and .module.scss
.
with-storybook-css-modules-app
It is configured with webpack5 (note: storybook is experimental now).
I'm referring to @joebartels' configuration. Thanks!
// .storybook/main.js
const path = require('path')
module.exports = {
stories: ['../stories/*.stories.@(ts|tsx|js|jsx|mdx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
webpackFinal: async (config) => {
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
auto: true,
},
},
},
'sass-loader',
],
include: path.resolve(__dirname, '../'),
})
return config
},
core: {
builder: 'webpack5',
},
}
Thank you @joebartels, I've one question left regarding your config. Does your config also support *.module.css
files or only *.module.scss
. I ran into several issues when trying to work with *.module.scss
in my next-scss-tailwind-postcss setup when using modules that do not need to be .scss files necessarily.
FTR: In the end I renamed all my *.module.css
files, but I wonder what's happening here. It worked without issues in next itself. 🤷
For those who do not need Sass, I created an example repo with Next.js + Storybook + Tailwind + CSS Module support that does not require to modify the webpackFinal
config.
Here is a git diff that focus on the setup.
@tidusia Thanks, your config worked like a charm. I have one question though, why is babel-core
and babel-loader
needed as mentioned in your diff.
Also, I would like to point out, that if you are using path aliases via typescript, be sure to check this part of the documentation:
https://storybook.js.org/docs/riot/configure/webpack#typescript-module-resolution
you saved my day
Amazing, thank you!
The clean solution, thanks @drskullster