SCSS Modules not properly loading in Storybook for my Nextjs app

Viewed 1867

Working on a new project using Nextjs and Storybook. We are using SCSS modules to style our components, and they work just fine in the actual app on the browser, but they won't link up in the stories themselves. Here are a few simple snippets to show where I'm at right now:

Component:

import React from 'react'
import styles from './VideoEntryTile.module.scss'

const VideoEntryTile: React.FC = () => {
    return (
        // This displays properly in the browser but not storybook
        <div className={styles.container}>
            <p>Hello</p>
        </div>
    )
}

export default VideoEntryTile

SCSS module:

.container {
    background-color: blueviolet;
}

Component story:

import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';

import VideoEntryTile from './VideoEntryTile';

export default {
  title: 'Video Entry Tile',
  component: VideoEntryTile,
  argTypes: {
  },
} as ComponentMeta<typeof VideoEntryTile>;

const Template: ComponentStory<typeof VideoEntryTile> = (args) => <VideoEntryTile {...args} />;

export const Primary = Template.bind({});

Primary.args = {};

./storybook/main.js:

module.exports = {
  core: {
    builder: 'webpack5',
  },
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)",
    "../src/components/**/*.stories.tsx"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    {
      name: '@storybook/preset-scss',
      options: {
        sassLoaderOptions: {
           modules: true
        }
      }
    }
  ],
  "framework": "@storybook/react"
}

Can anyone tell me where I'm going wrong? Thanks.

1 Answers

Create a file called scss-preset.js in .storybook:

// Copied from https://github.com/storybookjs/presets/blob/master/packages/preset-scss/index.js
function wrapLoader(loader, options) {
    if (options === false) {
       return [];
    }
 
    return [
       {
          loader,
          options,
       },
    ];
 }
 
 function webpack(webpackConfig = {}, options = {}) {
    const { module = {} } = webpackConfig;
    const {
       styleLoaderOptions,
       cssLoaderOptions,
       sassLoaderOptions,
       rule = {},
    } = options;
 
    return {
       ...webpackConfig,
       module: {
          ...module,
          rules: [
             ...(module.rules || []),
             {
                test: /(?<!module)\.s[ca]ss$/,
                ...rule,
                use: [
                   ...wrapLoader('style-loader', styleLoaderOptions),
                   ...wrapLoader('css-loader', {
                      ...cssLoaderOptions,
                      modules: false,
                   }),
                   ...wrapLoader('sass-loader', sassLoaderOptions),
                ],
             },
             {
                test: /\.module\.s[ca]ss$/,
                ...rule,
                use: [
                   ...wrapLoader('style-loader', styleLoaderOptions),
                   ...wrapLoader('css-loader', {
                      ...cssLoaderOptions,
                      modules: true,
                   }),
                   ...wrapLoader('sass-loader', sassLoaderOptions),
                ],
             },
          ],
       },
    };
 }
 
 module.exports = { webpack };
 

This is going through each scss file and, if it's a module.scss file, processing it differently than the ones that aren't.

in main.js, add presets: [path.resolve("./.storybook/scss-preset.js")], to module.exports. Should be all you need.

Related