sass-loader: Webpack sass loader does not recognize global variables file

I have this sass directory:

  • _vars.scss
  • main.scss

//main.scss

@import './vars';

In other js file i have:

require('./some-module-sass-file');

The problem is I have global variables in the vars file and the some-module-sass-file not recognize them and throw an error.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 8
  • Comments: 30 (1 by maintainers)

Most upvoted comments

I’m adding @import 'variables' using data:

  sassLoader: {
    data: '@import "variables";',
    includePaths: [
      path.resolve(__dirname, "./app")
    ]
  }

A note for webpack 2 and @natchiketa’s solution:

For loader options: webpack 2 no longer allows custom properties in configuration. Loaders should be updated to allow passing options via loader options in module.rules.

So I had to modify my webpack config like this to have global variables:

loaders: [
      ...
      {
        test: /\.scss/,
        use: [{
          loader: "style-loader"
        }, {
          loader: "css-loader", options: {
            sourceMap: true
          }
        }, {
          loader: "sass-loader", options: {
            sourceMap: true,
            data: '@import "variables";',
            includePaths: [
              path.join(__dirname, 'src')
            ]
          }
        }],
        include: path.join(__dirname, 'src')
      }
    ]

although the problme with that is we end up with nest head fuck…:

"../../../../../src/_varibles.scss"

if we restructure our directories… BOOM!

@evanjmg Couple of things: first, although it shouldn’t be an issue, since the docs say you can put the options there—I am putting them in an object called sassLoader, at the root of my webpack config’s exports, like this:

module.exports = {
  ...
  module: {
    loaders: [
      {
        test: /\.scss$/,
        loaders: ["style-loader", "css-loader", "sass-loader"]
      }
    ]
  },
  sassLoader: {
    includePaths: [path.resolve(__dirname, "./some-folder")]
  }
};

The second thing is what I think is causing it to not work for you. The @import statement needs to use a path relative to one of the includePaths paths. For example, if your _variables.scss is at src/app/styles/partials/_variables.scss, and your current includePaths only has src, then the @import has to be like this: @import('./app/styles/partials/variables');. It’s not just going to automatically traverse the entire tree.

Try something like this:

module.exports = {
  ...
  module: {
    loaders: [
      {
        test: /\.scss$/,
        loaders: ["style-loader", "css-loader", "sass-loader"]
      }
    ]
  },
  sassLoader: {
    data: '@import "variables";',
    includePaths: [
      path.resolve(__dirname, "./src/app/styles/partials")
    ]
  }
};

You could perhaps set the includePath to the directory where your stylesheet is, then import simply with @import 'variables'?

My advice:

Separate your Sass files into library files and application files. This means that you have Sass files that will output CSS (your application files) and you have Sass files that provide variables and mixins for them, but don’t produce any output. Then you write your application files in a modular way without implicit dependencies, but explicit ones which means that you can compile any application file and it will work without producing duplicate CSS.

Yes, this is the only way. It doesn’t work because variables work only within @imported Sass files. Just have a _globals.scss file with variables, functions etc. that you @import in each Sass file.

This is better anyway, because now each save won’t cause all Sass files to recompile, just the file you changed.

Just in case, here is my webpack dev config part for SASS

                        {
                            loader: 'sass-loader',
                            options: {
                                outputStyle: 'expanded',
                                sourceMap: false,
                                data: '@import "../src/styles/config/scss";',
                                includePaths: [ PATHS.src.root ]
                            }
                       }

@mrmnmly if you put actual css rules into this globally imported scss file, you will end up with repetitive code. This solution only works properly for sass variables and mixins, b/c those won’t directly appear in the final CSS.

data: @import '${path.resolve(__dirname, 'src', 'scss', 'import').replace(/\\/g, '/')}/variables'; This work for me, and resolve the absolute path question…