Can't compile sass while using Vue Storybook

Viewed 1818

I'm trying to create storybook on vue. My components written using sass. So, I made this in .storybook/main.js:

webpackFinal: (config) => {
        config.module.rules.push({
            test: /\.s[ac]ss$/i,
            use: [
                // Creates `style` nodes from JS strings
                'style-loader',
                // Translates CSS into CommonJS
                'css-loader',
                // Compiles Sass to CSS
                'sass-loader',
            ],
        })

        return config
}

And the styles looks like this:

<style lang="sass" scoped>
button
    background-color: red
</style>

So I'm getting this error when trying to compile:

SassError: Invalid CSS after "": expected 1 selector or at-rule, was "button"
        on line 1 of C:\Code\testproj\src\components\UI\TestComponent.vue

And if I change my style to this:

<style lang="sass" scoped>
button {
    background-color: red
}
</style>

All works, but that's not a sass syntax.

4 Answers

I was having this exact same issue and I was able to solve it. The issue is from the webpack config. If you're using SASS, your webpack.config.js file in your .storybook folder should look like this:

module.exports = ({ config }) => {
  config.module.rules.push({
    test: /\.sass$/,
    use: [
      require.resolve("vue-style-loader"),
      require.resolve("css-loader"),
      {
        loader: require.resolve("sass-loader"),
        options: {
          sassOptions: {
            indentedSyntax: true
          }
        }
      }
    ],
  });

  return config;
};

And if you're using SCSS, then it should be like this:

module.exports = ({ config }) => {
  config.module.rules.push({
    test: /\.scss$/,
    use: [
      require.resolve("vue-style-loader"),
      require.resolve("css-loader"),
      require.resolve("sass-loader"),
    ],
  });

  return config;
};

I was able to figure this out while reading the Vue Loader Docs

The problem is that in your webpack config, you are telling webpack that only use sass-loader when de extension of your file was test: /.s[ac]ss$/i That is to say .sass or .scss. However the extension of your file is .vue, because you are using sass in the vue file of your component.

With that configuration, try to put your sass style in a .sass file and check if works

For anyone using React 17+ with Storybook 6.4.9+, I had a similar problem where the Storybook/webpack build was not including my SCSS files. This configuration in .storybook/main.js worked for me:

module.exports = {
    "stories": [
        "../src/**/*.stories.mdx",
        "../src/**/*.stories.@(js|jsx|ts|tsx)"
    ],
    "addons": [
        "@storybook/addon-links",
        "@storybook/addon-essentials"
    ],
    "framework": "@storybook/react",
    webpackFinal: async (config) => {

        // add SCSS support for CSS Modules
        config.module.rules.push({
            test: /\.scss$/,
            use: [
                require.resolve("style-loader"),
                require.resolve("css-loader"),
                require.resolve("sass-loader"),
            ],
        });

        return config;
    }
}

I spend a lot of time to find better solution. It is may main.js config file for Storybook 6.4.9:

const path = require('path');

module.exports = {
  "stories": [
    "../src/**/*.stories.@(js|jsx|ts|tsx|mdx)"
  ],
  "addons": [
    "@storybook/addon-essentials",
    "@storybook/addon-actions",
    "@storybook/addon-controls",
    "@storybook/addon-links",
    {
      name: '@storybook/preset-scss',
      options: {
        sassLoaderOptions: {
          implementation: require('node-sass'), // ATTENTION: We need to use "node-sass" instead "sass/dart-sass"
          sassOptions: {
            indentedSyntax: true
          },
        },
      }
    },
    "@storybook/addon-postcss",
  ],
  "framework": "@storybook/vue",
  features: {
    babelModeV7: true,
  },
  webpackFinal: async (config, { configType }) => {
    // `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.
    
    // ATTENTION: Need to preload "global.sass" style for all elements;
    config.module.rules.map(rule => {
      if (rule.test instanceof RegExp && rule.test.toString() === '/\\.s[ca]ss$/') {
        rule.use.push({
          loader: require.resolve('sass-resources-loader'),
          options: {
            resources: [
              path.resolve(__dirname, '../src/styles/global.sass')
            ]
          }
        })
      }
      return rule
    })
    
    // ATTENTION: Need to compile "Pug" templates.
    config.module.rules.push(
      {
        test: /\.pug$/,
        oneOf: [
          // this applies to `<template lang="pug">` in Vue components
          {
            resourceQuery: /^\?vue/,
            use: ['pug-plain-loader']
          },
          // this applies to pug imports inside JavaScript
          {
            use: ['raw-loader', 'pug-plain-loader']
          }
        ]
      }
    );
    
    // Return the altered config
    return config;
  },
}
Related