Vue-loader: Load a global settings.scss file in every vue component?

Created on 27 Aug 2016  ·  154Comments  ·  Source: vuejs/vue-loader

I find myself repeating this same pattern in every component:

<style lang="scss">
  @import "../styles/settings.scss";

  .someclass { color: $some-variable; }
</style>

My settings.scss only contains variables. An additional pain point is that I have my components nested in several folders for better organization, so I always have to be careful to specify the path to my settings.scss properly. It'd be great if there was a way to globally include a settings.scss or similar file.

Most helpful comment

I'd ask to leave this open as the real issue is being able to use scss variables, mixins in component definitions. Although css automatically cascades down, if you wanted to use a globally defined sass variable inside your component, you will not be able to use the $variable synthaxx.

//global.scss
$white = '#fff'

//component.vue
<style>
.background {
  color: $white;
}
</style>

this will fail and a solution to this would turn my world around.

All 154 comments

I have the same question,but also have no answer.

I basically have the same question as well.

I do not know the answer to the main question (global scss load).

But regarding the additional pain point (adjust relative path), maybe you can mitigate it by configuring a Webpack alias.

You would use @import "styles/settings.scss" in all your files, having a webpack config like this:

{
  resolve: {
    alias: {
      styles: 'path/to/your/styles'
    }
  }
}

Docs:
https://webpack.github.io/docs/resolving.html
https://webpack.github.io/docs/configuration.html#resolve-alias

Neither of these solutions solves the fact that styles.scss will be repeated on your page for however many files you include it in. That just seems not thought out and very wasteful.

@ericcirone We have to differenciate:

Sharing Variables & Settings

The OP asked about importing a .scss for shared variables & settings.

Such a file usually does _not_ contain any CSS, but only SCSS $variables, mixins etc. (as stated by the OP himself) - so there would be _no_ repeated CSS in your final, compiled files.

Granted, it's tedious to add this @import statement in every component, but it does not change anything about filesize or performance.

Sharing styles

You wrote about importing styles.scss in multiple files - so , judging from the filename, you seem to ask how to deal with shared styles.

For this scenario, you simply do an import of the shared style file in your main.js file once. As CSS has no local scope, these styles will be available anywhere in your app so you don't have to import them anywhere else.

@jbruni The alias is a good solution to relative paths, yep! :+1:

But you should use an absolute path:

{
  resolve: {
    alias: {
      styles: path.resolve(__dirname, '../src/path/to/your/styles') // relative to the location of the webpack config file!
    }
  }
}

@LinusBorg i got ya! I'm new to Sass and Vue. My problem was that i'm building a project with Foundation and tried importing in the Foundation main app.scss in all my <style> blocks so I could use the Foundation variables and was getting repeating code everywhere.

@ericcirone under the current setup you have to go into the foundation scss folder and find the partials from the src folder that contain the variables and the mixins, then import those in every file. You likely do not need to import the entire main.scss file in every partial if that's what you are doing.

Clsoing as this issue seems to be solved.

I'd ask to leave this open as the real issue is being able to use scss variables, mixins in component definitions. Although css automatically cascades down, if you wanted to use a globally defined sass variable inside your component, you will not be able to use the $variable synthaxx.

//global.scss
$white = '#fff'

//component.vue
<style>
.background {
  color: $white;
}
</style>

this will fail and a solution to this would turn my world around.

I also think this should remain open. I'd love to be able to use global scss variables throughout components without importing every time.

Well, this is something that vue-loader is not suited to solve - it would have to be solved in sass-loader etc., because each pre processor might have a different syntax/ way of adding such a file.

Stylus-loader offers such a functionality, by the way.

@uptownhr well you can simply import your variables file in each component. It's a one-line copy&paste for each component, but it works.

@LinusBorg wrote

Stylus-loader offers such a functionality, by the way.

Can you point to an example of this with Stylus?

+1 to everyone asking for this issue to remain open, even if means waiting until a pull request eventually finds its way to sass-loader. This functionality should be a Vue product requirement, frankly.

Can you point to an example of this with Stylus?

This is not very well documented, I only read about it in a docs example for using a plugin:

https://github.com/shama/stylus-loader#using-nib-with-stylus

The import option will load the file "globally" as far as I have tested it.

+1 to everyone asking for this issue to remain open, even if means waiting until a pull request eventually finds its way to sass-loader.

We will not keep issues open for 3rd-party libs that we have no influence on, and likely won't require a change in vue-loader if they and in the 3rd-party lib (such changes would likely be implemented in loader configs, like the above import for stylus-loader, which vue-loader doesn't "care" about).

You will be better of asking for this in the respective loader's repos.

I too have the same problem. I really want to use a full Vue.JS Webpack stack on my next project. However.. not being able to import SASS variables is almost a deal breaker here. I guess for now I will compile global styles separately and use minimal styling in the components themselves.

There has to be a solution to importing variables and mixins no? Or making them globally available on compile?

I'm not sure if you missed it, so repeating myself again: you can of course simply @import your variables.

This threads was about doing that automatically, which is not possible and frankly, (repeating myself again, see previous reply) cannot be the job of vue-loader to provide that for all the available pre-processors.

I think you guys should seriously reconsider your position on this. At this point, SASS is the preprocessor of choice for at least 50% of devs (or a lot more, depending on which poll you're looking at). I really like keeping my components' css local to that component but it's a PITA when developing to have to import my settings.scss every time I start a new component, and having to take care to make the path right, and then it also makes the code slightly more verbose. Then if you ever move your component's path you have to update that import statement, etc. etc. Without this ability, I've resorted to the more traditional method of having all my scss files totally separate from the components, which defeats a good chunk of the the purpose of using vue-loader / .vue components IMO. Although to be totally fair I have not looked into the other options of getting this to work (such as the stylus one you linked). Either way, thanks for your work on this project.

You easily reduce the pain about the paths with a webpack alias, reducing the statement to e.g. @import "vars", working everywhere.

Considering the number of import statements we have in the JavaScript of most components, that should be manageable.

Adding this automatically with vue-loader would be a hack. For starters, `lang="sass" can mean SCSS or SASS syntax, depending on the sass-loader config. So which do we choose when we prep end the @import string to the content of the script tag? We would have to interpret the webpqck settings somehow, etc.

That's a fair point and I think a webpack alias can be a good "workaround". It's definitely more explicit to always use an import statement, which you could argue is better.

Great :)

quick question, when you @import 'vars' in all your components, will this bloat your build? Meaning, will webpack be able to compile this into a commons?

Concerning filesize, this has no influence if the imported file only contains SCSS variables and no actual CSS markup.

Concerning memory / compile speed, this should be so small as to be neglegable - I haven't seen any issues with it in dev.

There are other parts of the build process that should be optimized if you experience longer (Re)build times in dev. (vendor chunks, DLL splitting ..)

Is there anything more needed to get Webpack aliases working in .vue components?

I set a resolve.alias for my style directory as suggested above, and can import/require from a Javascript file, but if I do @import "styles/_vars.scss" in a .vue component, I get a “File to import not found or unreadable” error.

File structure:

webpack.config.js
src/
├ components/
│ └ my-component.vue
└ style/
  └ _vars.scss
// webpack.config.js
{
  resolve: {
    alias: {
      'styles': path.resolve(__dirname, './src/style/')
    }
  }
}
<!-- my-component.vue -->
<style lang="sass">
  @import "styles/_vars.scss";
</style>

I’ve tried all kinds of variations on the import directive with no success, and a direct alias to the variables file also produces an error.

It does work using an absolute path (no Webpack alias), but I’d like to avoid the fragility that introduces:

@import "./../style/vars";

Any help appreciated!

@import "~styles/_vars.scss";

works for stylus:
in webpack.config:

const stylus_var = path.resolve(__dirname, './client/styl/var.styl')

resolve: {
    alias: {
      stylus_var,
    }
  },

in *.vue:

@import '~stylus_var'

About style in vue project, Here's my solution(for now):

1、I have two separate scss file( src/css/style.scss & src/css/vars.scss )
"style.scss" is a common scss file, which styling the main layout and common style;
"vars.scss" define all the common variable ;

2、In Vue component(single page component), I import the vars.scss file as it needed

3、In webpack , I extract all components style , and combine with the style.scss, when I build, all style combine together perfectly

and for now, it works well , even though import the "vars.scss" file did a little extra job, but not bother too much.

and if there're another more perfectly solution, I glad to hear that.

Here's my main webpack config:

var ExtractTextPlugin = require("extract-text-webpack-plugin")
var extractSCSS = new ExtractTextPlugin({filename: 'css/style.css', disable: false, allChunks: true})
entry: {
    app: ['./css/style.scss', './main.js'],
    vendor: ['vue', 'vue-router', 'axios']
},
rules: [
    {
        test: /\.scss$/,
        use: extractSCSS.extract({
            fallback: "style-loader",
            publicPath: "/",
            use: ['css-loader', 'sass-loader', 'postcss-loader']
        })
    },
    {
        test: /\.vue$/,
        loader: 'vue-loader',
        include: path.join(__dirname, "src"),
        exclude: /node_modules/,
        options: {
            loaders: {
                scss: extractSCSS.extract({
                    use: ['css-loader', 'sass-loader', 'postcss-loader'],
                    fallback: 'style-loader'
                })
            }
        }
    },
]

Well, I have a problem.
Two .vue file.
a.vue b.vue
In a.vue, I define some vars.(scss)
And how can I use these vars in b.vue without making another .scss file???
This problem happens when I try to write a module for vue.
b.vue is a file in module, so it can't be changed.
a.vue is a file in project, and I want to define some vars for b.vue.
Sorry for my bad English. :(

Problem can be solved by following way:
1) include global styles in every *.vue file (webpack aliases can be helpfull as described before)
2) remove dublicating in resulting file by optimize-css-assets-webpack-plugin

NOTE: scoped style in vue component can block styles merging

I was able to do this today using sass-resources-loader as per @sqal 's suggestion.

I changed vue-cli's familiar loaders block from the default:

loaders: { 
  sass: 'vue-style-loader!css-loader!postcss-loader!sass-loader?indentedSyntax=1', 
  scss: 'vue-style-loader!css-loader!postcss-loader!sass-loader', 
} 

...to the array/object syntax that you'd use in module.rules.use. Here's my entire block for vue-loader:

{
  test: /\.vue$/,
  use: {
    loader: 'vue-loader',
    options: {
      loaders: {
        sass: [
          'vue-style-loader',
          'css-loader',
          'postcss-loader',
          'sass-loader?indentedSyntax=1',
          {
            loader: 'sass-resources-loader',
            options: {
              resources: path.resolve(__dirname, 'app/src/renderer/styles/variables.scss'), // for example
            },
          },
        ],
        scss: [
          'vue-style-loader',
          'css-loader',
          'postcss-loader',
          'sass-loader',
          {
            loader: 'sass-resources-loader',
            options: {
              resources: path.resolve(__dirname, 'app/src/renderer/styles/variables.scss'), // for example
            },
          },
        ],
      },
    },
  },
},

Note that I also added postcss-loader but you don't have to, and that your resources can also be an array.

edit: So now any <style lang="scss"> (or sass) tag will have my variables.scss file available.

@foundryspatial-duncan, thanks for offering a solution to this issue.
However, I just tried this and it doesn't seem to work on my side

This is the base config webpack file which came with the cli

var path = require('path')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src')
    }
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}

I went into the vueLoaderConfig file to add your code because that's where all the options go (I only added the scss part since I don't plan to use the sass syntax)

var utils = require('./utils')
var config = require('../config')
var isProduction = process.env.NODE_ENV === 'production'
var path = require('path')


module.exports = {
  loaders: utils.cssLoaders({
    sourceMap: isProduction
      ? config.build.productionSourceMap
      : config.dev.cssSourceMap,
    extract: isProduction,
  }), scss: [
        'vue-style',
        'css',
        'sass',
        {
          loader: 'sass-resources-loader',
          options: {
            resources: path.resolve(__dirname, 'assets/styles/variables.scss')
          }
        }
      ]

}

and this is the utils.cssLoaders file

var path = require('path')
var config = require('../config')
var ExtractTextPlugin = require('extract-text-webpack-plugin')

exports.assetsPath = function (_path) {
  var assetsSubDirectory = process.env.NODE_ENV === 'production'
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory
  return path.posix.join(assetsSubDirectory, _path)
}

exports.cssLoaders = function (options) {
  options = options || {}

  var cssLoader = {
    loader: 'css-loader',
    options: {
      minimize: process.env.NODE_ENV === 'production',
      sourceMap: options.sourceMap
    }
  }

  // generate loader string to be used with extract text plugin
  function generateLoaders (loader, loaderOptions) {
    var loaders = [cssLoader]
    if (loader) {
      loaders.push({
        loader: loader + '-loader',
        options: Object.assign({}, loaderOptions, {
          sourceMap: options.sourceMap
        })
      })
    }

    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
  }

  // https://vue-loader.vuejs.org/en/configurations/extract-css.html
  return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
  }
}

// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
  var output = []
  var loaders = exports.cssLoaders(options)
  for (var extension in loaders) {
    var loader = loaders[extension]
    output.push({
      test: new RegExp('\\.' + extension + '$'),
      use: loader
    })
  }
  return output
}

Any idea why?

Ah, the example I gave was actually from an electron template but it will work in the webpack-simple one too.
For the main webpack template, I think you'd need to modify the generateLoaders function in utils.js.

You basically want to add this object:

{
    loader: 'sass-resources-loader',
    options: {
        resources: path.resolve(__dirname, 'path/to/variables.scss'), // for example
    },
}

to the end of the array that generateLoaders returns for scss.
Another approach would be to maybe do a push or a concat on this line:

    scss: generateLoaders('sass'),

I can confirm that this works, thanks!

```javascript
scss: generateLoaders('sass').concat(
{
loader: 'sass-resources-loader',
options: {
resources: path.resolve(__dirname, '../src/style/variables.scss')
}
}
),

It would be great if anyone could submit a PR to include the solution to this page since it seems to be quite a common request.

@foundryspatial-duncan & @NLNicoo amazing solutions. Thank you

I saw this and decided I wanted to:

  • explicitly import my scss variables file in each .vue file
  • create a webpack alias so I didn't have to bother with the path to this file every time

I noticed that since I used vue-cli to generate my project, I already had an alias to the src folder.

in webpack.base.conf.js:

  resolve: {
   // snip...
    alias: {
      // snip...
      '@': resolve('src')
    }
  },

So @ in an import points to the src folder. And all I had to do was:

  • Put scss variables in a file located here: src/variables.scss.
  • Use them in any .vue file like this:
<style lang="scss">
@import '~@/variables.scss';

div {
  background-color: $a-variable-from-the-file;
}
</style>

... in case that helps anybody else.

@dad700, that is awesome! Works for .stylus files, too. This was the simplest solution to date.

For anyone trying to figure out why you need to use a tilde ~ to make aliases work check this issue in css-loader:

https://github.com/webpack-contrib/css-loader/issues/12

css @import is relative to the current directory. For resolving "like a module" you can prefix ~.

AFAIK it's not documented anywhere.

@dad700, that is perfect! Clean & minimal solution. Big 👍 from me for not over-engineering.

From the /build folder in the project, i went to utils.js and inside the generateLoaders() function, I added this

// This makes my vars and mixins avail throughout my app at a global level
    if (loader === 'sass') {
      loaders.push({
        loader: 'sass-resources-loader',
        options: {
          resources: [
            path.resolve(__dirname, '../src/styles/vars.scss'), 
            path.resolve(__dirname, '../src/styles/mixins.scss')
          ]
        }
      })
    }

make sure you also run npm install --save-dev sass-resources-loader
Last thing is to make sure those files exist or you'll get a compile error. i put them in /src/styles but you can change those lines to put em wherever! OH, also pay attention to the order I have in my resources array. I wanted the vars to get parsed first so that they would be avail to be used from within the mixins. Thanks everyone!

:)

I'm trying to use material-component-web in my project with webpack-simple-template. I have successfully include ' @import "material-components-web/material-components-web"; ' in my .vue file with this webpack config:

 loaders: {
    scss: [
        'vue-style-loader', 'css-loader', 
        {
             loader: 'sass-loader',
             options: {
                 includePaths: ["./node_modules"]
             }
        }, {
         ...

but it doesn't has a global effect. I still have to import material-components-web or @material/...( individual component ) in every .vue file. As @foundryspatial-duncan suggested, I use sass-resource-loader to load a style.scss file which will import whole material-component-web library. Here is my webpack.config.js

{
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                        sass: ['vue-style-loader', 'css-loader', {
                            loader: 'sass-loader',
                            options: {
                                includePaths: ["./node_modules"],
                                indentedSyntax: true
                            }
                        }, {
                                loader: 'sass-resources-loader',
                                options: {
                                    resources: [
                                        path.resolve(__dirname, './src/style.scss'),
                                    ],
                                    includePaths: ["./node_modules"]
                                }
                            }],
                        scss: ['vue-style-loader', 'css-loader', {
                            loader: 'sass-loader',
                            options: {
                                includePaths: ["./node_modules"]
                            }
                        }, {
                                loader: 'sass-resources-loader',
                                options: {
                                    resources: [
                                        path.resolve(__dirname, './src/style.scss'),
                                    ],
                                    includePaths: ["./node_modules"]
                                }
                            }]
                    }
                }
            }

and here is my src/style.scss file

@import "material-components-web/material-components-web";

$mdc-theme-primary: #4eadff; //override default
$mdc-theme-accent: #ff4081;
$mdc-theme-background: #c5ff83;

Error:

ERROR in ./node_modules/sass-loader/lib/loader.js?{"includePaths":["./node_modules"]}!./node_modules/sass-resources-loader/lib/loader.js?{"resources":["/home/sand/Data/sand/Downloads/vue-practice/module2/src/style.scss"],"includePaths":["./node_modules"]}!./node_modules/vue-loader/lib/style-compiler?{"vue":true,"id":"data-v-1d1f6298","scoped":true,"hasInlineConfig":false}!./node_modules/vue-loader/lib/selector.js?type=styles&index=0!./src/components/Header.vue
Module build failed:
<template>
^
      File to import not found or unreadable: ../material-components-web/material-components-web.

although I have added an includePaths option under sass-resources-loader in webpack.config.js file, webpack could not find material-components-web under node_modules folder . So my question is how to load a global variables scss file which contain an @import to a third-party library to get that library's variables and mixins ? I had take a look at their vue example but since they use webpack 1, most option is not work in webpack 2,3

I solved it. I forget to put '~' sign at import path like this

@import "material-components-web/material-components-web";

Sorry everyone

That is how I import my vars and mixins sass files globally in my vue templates:

{
  loader: 'sass-loader',
  options: {
    indentedSyntax: true,
    sourceMap: true,
    outputStyle: 'compressed',
    includePaths: ['./app/sass', './app/sass/partials'],
    data: '@import vars\n@import mixins'
  }
}

Hope this helps someone.

@eduardocmoreno awesome find! better than sass-resources-loader suggested above, which is just adding another dep.

How does it work with Browserify?

@polikin vue-loader is a Webpack loader.

For Browserify you should be using this: https://github.com/vuejs/vueify

@anish000kumar that solution worked for me but I realized that the styles for any component that I used global SCSS in wasn't being extracted a separate style.css that contains all of the app's styling. Instead, it's inserted into the site via style tags. Any reason why that might be the case?

I have a global.scss file in a styles/scss folder that imports a lot of smaller global SCSS files, including variables, mixins, and actual styling I want applied across the app.

In webpack.config.js my vue-loader configuration looks like this:

{
  test: /\.vue$/,
  exclude: /(node_modules|bower_components)/,
  loader: 'vue-loader',
  options: {
    extractCSS: true,
    loaders: {
      scss: 'vue-style-loader!css-loader!sass-loader?data=@import "./static/styles/scss/global.scss";'
    }
  }
}

@tomanistor I have updated my answer in detail over here -
https://stackoverflow.com/a/46015906/5013932
I guess it would help you. You would want to look into utils/build.js to see how webpack spits the CSS in a separate stylesheet. A quick look reveals this:

  // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
      return ExtractTextPlugin.extract({
        use: loaders,
        fallback: 'vue-style-loader'
      })
    } else {
      return ['vue-style-loader'].concat(loaders)
    }
  }

I guess that should suffice would needs :)

I found a very simple solution (project started with vue cli) for importing specific .scss files globally into .vue template files.

If you mix @dad700's and @eduardocmoreno's answers, you can simply do the following:

In the project/build/utils.js file we have this on row 62:
scss: generateLoaders('sass'),

we can replace it with this:

scss: generateLoaders('sass', {
  data: "@import '~@/path/to/settings';\n",
}),

... and this will import (i.e.) project/src/path/to/_settings.scss

Hey @zArubaru why the underscore in _settings.scss but not in ~@/path/to/settings? Is it a typo?

@PierBover
From the sass guide:

The underscore lets Sass know that the file is only a partial file and that it should not be generated into a CSS file. Sass partials are used with the @import directive.

You can skip the file extension and preceding underscore for the import statement.

For me the data attribute did the trick.

// Configuration for the ExtractTextPlugin.
const extractConfig = {
  use: [
    { loader: "raw-loader" },
    {
      loader: "postcss-loader",
      options: {
        plugins: [require("autoprefixer")]
      }
    },
    {
      loader: "sass-loader",
      options: {
        outputStyle:
          "production" === process.env.NODE_ENV ? "compressed" : "nested",
        data: "@import './path/to/variables.scss';\n"
      }
    }
  ]
};

Thank you guys for solutions.
A little improvement on @zArubaru solution.
We can separate files into vars.scss, mixins.scss or global.scss and import them in index.scss.

// index.scss
@import "./vars";
@import "./mixins";
@import "./global";
// import other global styles
// build/utils.js
scss: generateLoaders('sass', {
  data: '@import "~@/assets/style/index";'
}),

After few hours I found the solution!

_I found it at:_
https://vue-loader.vuejs.org/en/configurations/pre-processors.html

So, If you are using vue-cli, do next steps:

1. Create file with global variables. In my case it was:
/src/styles/global_styles.scss
Example of content of global_styles.scss:

$firstColor: #44B3C2;
$secondColor: #F1A94E;
$thirdColor: #E45641;

2. Install "sass-resources-loader"
npm i sass-resources-loader --save

3. Edit /build/utils.js.

Replace:
scss: generateLoaders('sass')

By:

scss: generateLoaders('sass')
      .concat(
        {
          loader: 'sass-resources-loader',
          options: {
            resources: path.resolve(__dirname, '../src/styles/global_styles.scss')
          }
        }
      ),

where'../src/styles/global_styles.scss'should be path to your scss file!

4. Rebuild webpack
npm run dev

5. Try to use global variables in every vue component!

_I hope my solution is not complicated =)_

@VladPavliuk, This worked for me.

Thank you for this solution. I am using 'webpack-simple' template and the re is no ./build/util.js file. Where would you place this in the default webpack.config.js file?

@dosstx, where sass-loader is defined.

@dosstx , Hello!) For simple-webpack template the solution is next steps:

1. Create file with global variables
/src/styles/global_styles.scss

2. Install "sass-resources-loader"
npm i sass-resources-loader --save

3. Edit /webpack.config.js:
Find array 'scss' (near 44 line):

'scss': [
              'vue-style-loader',
              'css-loader',
              'sass-loader',
     ],

Add 4-th element (object) to this array, so result array should looks like this:

'scss': [
  'vue-style-loader',
  'css-loader',
  'sass-loader',
  {
    loader: 'sass-resources-loader',
    options: {
      resources: path.resolve(__dirname, './src/styles/global_styles.scss')
    }
  },
],

Add the same object to 'sass' array (near 55 line), so the 'sass' array should looks like this:

'sass': [
  'vue-style-loader',
  'css-loader',
  'sass-loader?indentedSyntax',
  {
    loader: 'sass-resources-loader',
    options: {
      resources: path.resolve(__dirname, './src/styles/global.scss')
    }
  },
]

4. Restart app:
ctrl + c
npm run dev

_Hope this steps will help you)_

@VladPavliuk Fantastic! Thank you!

I noticed that after implementing the above code, my Chrome Vue DevTools extension no longer works? Can anyone confirm that it works for them when using sass-resources-loader?

@dosstx seems to work fine for me. I just put the change in as well outlined by @VladPavliuk

@ericcirone are you using the webpack-simple template? Not sure if it matters, but can you share your webconfig file to make sure I did this correctly?

@VladPavliuk Unfortunately this solution still duplicates CSS.

@tomanistor Do you mean that scss file should always been imported?

@VladPavliuk My trouble is that I'm not importing just SCSS variables and mixins, but global styles also, which are then duplicated for each component. I'm trying to find a way to have a global SCSS file that can be more than just variables and mixins.

@tomanistor , when you say "styles", do you mean css selectors and rules?

@tomanistor that is a different issue, I would start a different thread. this request is specfically just for mixins/variables and has been solved for that case.

@VladPavliuk it sounds like you should separate your global styles from your SCSS vars/functions/partials.

Just import your global styles in your App.vue component.

If you have things OTHER than variables and mixins you definitely want to make sure to only include it once. I put my global styles in something like /scss/main.scss, then include it just once in my main App.vue:

<style lang="scss">
@import './scss/main.scss';
</style>

in that same file I am importing my settings.scss which is what I'm auto-importing into other components, but again, that settings.scss file is ONLY variables/mixins.

@westwick thanks, that sounds like a good solution!

@westwick I am using the bootstrap.scss global variables and imported that into my own custom.scss file. This is how I have it set up in my custom.scss file:

$secondary: #868e96;
$success: #0d9346;
$green: #0d9346;
$teal: #32a6ad;
$info: $teal;
$dark: #4f4f4f;

// Bootstrap and its default variables
@import "./node_modules/bootstrap/scss/bootstrap";

I have to do an import of custom.scss in all of my components in order to get that to work. So, you guys are saying that you only have to do that in your main app.vue file? I tried that and it didn't work for me -- have to import it every time in all of my components.

there are two issues being discussed at this point which is making it confusing.

If you are trying to load JUST VARIABLES OR MIXINS into EVERY COMPONENT, then you should use the method discussed earlier in the thread and now outlined officialyl in the docs, under 'loading a global settings file': https://vue-loader.vuejs.org/en/configurations/pre-processors.html

If you are trying to load global scss which includes actual css properties, I recommend personally doing the way I just described by importing it ONCE in your app.vue.

I believe in your case @dosstx that that import for bootstrap may include basic css rules so you probably do not want to include in a custom.scss as it means all those rules will be duplicated everywhere, but I haven't use bootstrap in a while to know. You may need to extract the variables out of bootstrap if you are e.g. trying to access their media queries in every component without having to import it every time. This is more specific to bootstrap so I can't say too much else.

Importing global styles in App.vue, main Vue component solves the problem. This allows us to use styles from all globals, but still, we couldn't use variables in Vue components.

To get variables, use solution from https://vue-loader.vuejs.org/en/configurations/pre-processors.html called Loading a global settings file.

Best, M.

FYI, if you are using vue-electron, all you have to do is update webpack.renderer.config.js

where it loads the 2 sass,scss strings. Just replace it with this.

sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1&data=@import "./src/styles/globals"',
scss: 'vue-style-loader!css-loader!sass-loader?data=@import "./src/styles/globals";'

Make sure this file doesn't output anything, it should only have variables and mixins.
In your App.vue you can still add this, which can have normal tags and such.

<style lang="scss">
   @import '../styles/main.scss';
</style>

plugins: [
new webpack.LoaderOptionsPlugin({
options: {
stylus: {
import: [path.resolve(__dirname, '../src/assets/stylus/colors.scss')]
}
}
})
]

@elonbase
Where to add these?
Provide more details.

https://github.com/jonathantneal/postcss-preset-env

Solved my problem with CSS variables on App.vue.

@hosein2398
Add this in your webpack configurations.

<script type="text/javascript">
import 'base.scss'
import 'common.scss'

it's simple and awefull, but it works.

@trusktr That is not relevant to this issue which has already been solved and closed, I would open a new issue.

Here's a question: suppose I have component A with it's own Sass styles. Then I want to make a component B that extends some styles from component A. This will lead to duplicate CSS in the output.

This issue is about loading a global .scss file into every component. You are talking about something different.

Warning: it's probably a better idea to use @Achronius solution

For any one that's using @vue/cli 3.0 this is the solution I came up with:

// vue.config.js
const path = require("path");

module.exports = {
  chainWebpack: config => {
    config.module
      .rule("vue")
      .use("vue-loader")
      .tap(options => {
        const loader = {
          loader: "sass-resources-loader",
          options: {
            resources: path.resolve(__dirname, "src/variables.scss")
          }
        };
        options.loaders.scss.push(loader);
        options.loaders.sass.push(loader);
        return options;
      });
  }
};

So my use case is I have Laravel Mix and I want to be able to re-use components with minimal editing to electron vue. I got it to work this way.

In my webpack.mix.js file I added the following options:

.options({
      processCssUrls: false,
      extractVueStyles: true,
      globalVueStyles: './resources/assets/sass/utils/_variables.scss'
   });

The two to take note of are the extractVueStyles & globalVueStyles. extractVueStyles extracts the styles to a "dedicated file" and this must be enabled for globalVueStyles. globalVueStyles is the URL to the styles to be imported to EVERY Vue component. In this case, I simply include my _variables.scss file which contains just the sass variables I use. More information can be found here: https://github.com/JeffreyWay/laravel-mix/blob/master/docs/options.md.

For those using mix, I had to install: https://github.com/shakacode/sass-resources-loader as well.

For anyone NOT using mix, maybe some of the source of laravel mix with this part could help configure and set up the environment correctly? Let me know if this helps!

@ocboogie with @vue/cli 3.0.0-beta.10 your solution does not work, maybe by migration to webpack4 options.loaders == undefined.
But something like that works

// vue.config.js
const path = require('path')
const loader = {
  loader: 'sass-resources-loader',
  options: {
    resources: path.resolve(__dirname, './src/assets/scss/_variables.scss')
  }
}
module.exports = {
  configureWebpack: {
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: [
            loader,
            'sass-loader'
          ]
        }
      ]
    }
  }
}

For Vue CLI 3 you should use the css.loaderOptions option.

After a long time researching this issue I finally settled on a solution that will work for me and the team.

Basically we are using sass-resources-loader to load a stylesheet that contains references to mixins and variables only. App.vue has an import for the rest of the styles.

Just because this still gains traction: In Vue CLI 3 in your _vue.config.js_ file, just add the following, copied from the Official Vue CLI 3 Docs
```
// vue.config.js
const fs = require('fs')

module.exports = {
css: {
loaderOptions: {
sass: {
data: fs.readFileSync('src/variables.scss', 'utf-8') //your-path-here
}
}
}
}`

@Achronius This solution does not have hot reloading. Is there any way to solve this problem?

If you want to take advantage of chaining, you can include the following in your vue.config.js file:

const fs = require('fs');

module.exports = {
  chainWebpack: (config) => {
    config.module.rule('scss').oneOf('normal').use('sass-loader').tap(options => ({
      ...options,
      data: fs.readFileSync('./src/_variables.scss', 'utf-8'),
    }));
  },
};

There is a mention of global variables in the vue-loader docs here: https://vue-loader.vuejs.org/guide/pre-processors.html#sharing-global-variables.

@reesexu If you want hot-reloading you can use sass-resource-loader:

// vue.config.js
module.exports = {
  chainWebpack: (config) => {
    config.module
      .rule('scss')
      .oneOf('normal')
      .use('sass-resources-loader')
      .loader('sass-resources-loader')
      .options({
        resources: './src/_variables.scss',
      });
  },
};

Note: The above examples are for vue-cli@3.

@reesexu @Achronius Instead of using fs.readFileSync you can use @import (using vue-cli@3):

module.exports = {
  css: {
    loaderOptions: {
      sass: {
        data: '@import "src/style/base.scss";'
      }
    }
  }
}

chaining: ✅
hot reloading: ✅

@hurradieweltgehtunter @chipit24 Thank you for your answer and @hurradieweltgehtunter 's solution solved my problem perfectly!

@hurradieweltgehtunter Thank you for your advice, but I found issue with sass builtin functions, as example background-color: rgba($primary, .8); or background-color: lighten($primary, 20%);.
Anyways your solution is the best for me at this moment.

@codev0 whats the issue? How did you declare $primary ?

I have dependencies (which I do not control) that mix css styles, variables and mixins. I need all of these installed globally (once). If I use sass-resource-loader or the css.loaderOptions solutions the css styles will be injected everywhere I have a a <style> block. This is obviously very bad as rules will be duplicated everywhere. If I just import these dependencies into my main App.vue file the styles will be applied globally but the mixins and variables will not be available in other modules so I would still need to @import at the top of all my <style> blocks. Which is identically bad.

Is there a solution that imports styles, mixins and variables once and made available globally?

@dsteinbach if that is how your dependencies styles are packaged, I don't think there is much you can do. ask them to restructure so you can import vars/mixins separate from styles? 😂

You were supposed to be the chose one

Haha not really anything to do with Vue, but just how your depedency's css is structured. For example a good css library should export it's vars/mixins separate so you can import them as needed and avoid exactly the problems you stated, e.g. with bulma they provide the ability to @import "~bulma/sass/utilities/_all.sass"

What ended up working for me is adding the following code in webpack.base.conf.js (right after module):

var webpack = require('webpack') // Do not forget to add this dependency, or else you will get an error

// ...

plugins: [
  new webpack.LoaderOptionsPlugin({
    options: {
      stylus: {
        import: [path.resolve(__dirname, '../src/styles/main.styl')]
      }
    }
  })
]

In main.styl I have all the @import of variables, mixins, functions, etc.

Source: https://badacadabra.github.io/Using-global-style-rules-in-a-Vue-js-app/

Went all over the Internet looking for the Stylus solution with Vue CLI 3 and loaderOptions. That's what helped me in the end (turns out, I needed the "path" package):

const path = require('path');

module.exports = {
    css: {
        loaderOptions: {
            stylus: {
                import: [
                    path.resolve(__dirname, './src/styles/variables.styl')
                ]
            }
        }
    },
    lintOnSave: false
}

@westwick

I'm using Bulma right now, but the problem with this is it bloats your build.
For example, let's say I want to use the responsive mixins as well as have access to all style variables.
So I do; @import "~bulma/sass/utilities/_all.sass"

However, this does not include only variables. It includes mixins with actual code.
Now imagine I have 100 components. I'm importing it to every single component. I now have 100x more bloat than I previously would have had.

Where as, if you could just import it ONCE and then reference to that one import from components, then you only have the original code and no duplicates.

@marbuser Mixins do not get converted to actual css so this is not a problem. The only thing you want to be careful is that no css rules are in that type of file, because that WILL lead to the kind of bloat you mentioned. For Bulma, I am pretty sure that the utilities folder does not contain any actual css rules, just functions, mixins and variables.

@westwick
Yeah just noticed this. It seems the only stuff that gets repeated is the animation stuff (which you can just exclude.)

I did have a question you might be able to help with though.
In my vue.config.js file, I've got it setup like this; (Since this is apparently he 'recommended setup')

  css: {
    loaderOptions: {
      sass: {
        data: '@import "~bulma/sass/utilities/_all.sass";',
      },
    },
  },

However, this causes me to be unable to change variables. For example, let's say I set $primary to Red. Well whenever I use the setup above, it resets (since I'm reimporting initial-variables I think?), and I'm not able to do any customisations.

Are you aware of anyway around this? (Or if you can recommend a better config setup for CLI 3?)

Thanks

@marbuser yea you have to set that up in a seperate stylesheet and then import that. I haven't tried providing that file to css loaderOptions though, I normally just import it in my base vue component.

@westwick Well in my main scss file that I import into my App.vue, I import the whole of bulma, but I still have to import the utilities and such individually in other components if I want to use them. So even though I've imported ~bulma in App.vue, I will still need to import ~bulma/sass/utilities/_all.scss in all my other components in order to be able to use the mixins and such.

Could you perhaps provide an example of a setup you have that is working?

@Justineo How would you go about using this with CLI 3? Since it uses vue.config.js and not "normal" webpack?

EDIT:
For example, I'm using this in vue.config.js, but it appears to not be working at all.

      {
        test: /\.scss$/,
        use: ['sass-loader', {
          loader: 'style-resources-loader',
          options: {
            patterns: [
              path.resolve(__dirname, '~bulma/sass/utilities/mixins.sass'),
            ],
          },
        }],
      }],
    },

It is documented in the latest CLI docs: https://cli.vuejs.org/guide/css.html#automatic-imports.

@Justineo Yeah I tried using that as well. However it gives me very bizarre errors that I'm unable to figure out, because they don't make any sense.

For example, I get this result using the same setup on the cli docs but just changing stylus to scss;

<template>
       ^
      Invalid CSS after "@charset": expected 1 selector or at-rule, was '"utf-8"'
      in /src/components/sections/About.vue (line 1, column 9)

and if I change it to a different file and not _all.sass, it get something like;

    <app-hero/>
^
      Media query expression must begin with '('
      in /src/App.vue (line 3, column 1)

As you can see, both these errors make 0 sense. Why would there even be a media query inside of my <template> section????

So I was just trying the new cli and ran into this issue as well. I was getting weird errors similar to @marbuser except in the script section, for example:

Syntax Error: SyntaxError: T:\Code\test\src\main.js: Invalid number (1:6)

> 1 | $var: 1emimport Vue from 'vue'
    |       ^
  2 | import App from './App.vue'

Turns out I had installed the vue-cli-plugin-style-resources-loader plugin using npm (old habits die hard) and since I added the example config in the documentation manually I did not have the preProcessor option set.

I uninstalled everything (because I did not know that was the problem) and added the plugin with vue, at which point I noticed the extra preProcessor option had been set (because adding through vue will prompt you to pick your pre-processor).

Everything seems to be working perfectly now.

How is this so complicated? I just want to load a .scss file globally.

https://github.com/nguyenvanduocit/vue-cli-plugin-style-resources-loader/#readme

vue add style-resources-loader
const path = require('path')
module.exports = {
  pluginOptions: {
    'style-resources-loader': {
      preProcessor: 'scss'
      patterns: [
        path.resolve(__dirname, 'src/path/var.scss'),
        path.resolve(__dirname, 'src/path/mixin.scss'),
      ]
    }
  }
}

Simple and works !

I tried the following, it works but on build I get the styles repeated for every component. How can I just import once? This is so confusing.

 const path = require('path')

 module.exports = {
    pluginOptions: {
        'style-resources-loader': {
            preProcessor: 'scss',
            patterns: [
                path.resolve(__dirname, 'src/assets/main.scss'),
            ]
        }
    }
 }

It seemed like a few people were still getting stuck on this one (I know I did), so I wrote up a step by step post on it. I'll eventually make a cookbook entry in the docs too. Hope it's helpful :)

https://css-tricks.com/how-to-import-a-sass-file-into-every-vue-component-in-an-app/

Does the article apply to apps made with CLI 2.0 also @sdras?

I tried the following, it works but on build I get the styles repeated for every component. How can I just import once? This is so confusing.

 const path = require('path')

 module.exports = {
  pluginOptions: {
      'style-resources-loader': {
          preProcessor: 'scss',
          patterns: [
              path.resolve(__dirname, 'src/assets/main.scss'),
          ]
      }
  }
 }

I have the same problem if i use style in component... If i only use .scss file imported, its works...

Can't believe this has been running for more than 2 years and still no simple solution to import a single SCSS file with a pyramid structure into your vue app?

I don't see your point, there's loaders that do this, as demonstrated above. What about the original problem is left?

I'm surprised this is still an issue for people. Here's what works for me.

Webpack

{
        test: /\.(css|scss)$/,
        use: [
          {
            // Adds CSS to the DOM by injecting a `<style>` tag
            loader: 'style-loader'
          },
          {
            // Interprets `@import` and `url()` like `import/require()` and will resolve them
            loader: 'css-loader',
            options: {
              sourceMap: true
            }
          },
          {
            // Loads a SASS/SCSS file and compiles it to CSS
            loader: 'sass-loader',
            options: {
              sourceMap: true,
              data: '@import "./src/scss/vue-globals";'
            }
          }
        ]
      }

Then in my vue-globals.scss file I load in my bootstrap variables, mixins, functions and anything else that doesn't generate code but is necessary for common styling features.

@import "~bootstrap/scss/functions";
@import "vendors/bootstrap-variables";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins";
@import "mixins/index";

Then all those imports will be available within your vue components.
```

I don't see your point, there's loaders that do this, as demonstrated above. What about the original problem is left?

No, there aren't. There are about 15 different approaches "demonstrated" above, but they all suffer from caveats other issues that shouldn't be happening:

anything else that doesn't generate code

styles repeated for every component

bizarre errors that I'm unable to figure out

And:

I'm surprised this is still an issue for people. Here's what works for me.

The feedback is clear from this thread:

How is this so complicated? I just want to load a .scss file globally

The Vue documentation isn't clear on how to do this. It only talks about automatic imports, which is not what we're asking for. We don't want something that gets imported and repeated for every component. We just want to include a single global scss file, once, and be able to use the resulting variables etc. in all our components.

The documentation only has stylus examples. And the reference to the vue-cli-plugin-style-resources-loader is pretty useless as well. I've tried it, but it didn't do anything. The documentation for it is non existent, and it's unclear what the basic example does or is supposed to do if you're not intimately familiar with Webpack/Vue.

I have followed several of the suggested approaches in this thread and tried several more from whatever info I could piece together. None of them do what is needed:

  • One global SCSS import which itself imports other SCSS files
  • Variables and mixins available in all components
  • Overrides included once, after all components
  • Ability to include global one time use code-generating CSS

For developers with years of experience coming from build tools where these kind of problems are trivial to solve, it's a bit of a shock finding out that it either can't be done or is so complicated that it warrants a 2 year old github issue with still no clear, well documented, easy to apply solution.

So that's why people are still having issue with it.

We just want to include a single global scss file, once, and be able to use the resulting variables etc. in all our components.

well, that's not possible with webpack. Each style element results in a separate import statement that imports the styles into your bundle.

And each of those import statements is a separate preprocessor run.

That's not specific to Vue either.

When you import two different scss files in a .js file, the second one will not inherit variables etc. from the first.

So the answer to your question about how vue-loader hasn't solved this for you is that it can't because of the way imports of styles work in webpack.

If you want to have one global scss file and are not comfortable with the other ways laid out in this issue, then only use one global scss file, don't use <style> tags in .vue files and instead write your component styles in scss partials. That's totally possible.

Thanks, if that's the case then we'll probably work with that approach.

The documentation here is very very helpful and easy to understand.
https://cli.vuejs.org/guide/css.html#passing-options-to-pre-processor-loaders

I was able to solve these problems:

  • One global SCSS import which itself imports other SCSS files
  • Variables and mixins available in all components
  • Overrides included once, _after_ all components
  • Ability to include _global_ one time use code-generating CSS

by doing this:
1)Importing variables, mixins and other sass things that will be removed after compiling. Import in vue.config.js:

module.exports = {
  css: {
    loaderOptions: {
      // pass options to sass-loader
      sass: {
        // @/ is an alias to src/
        // so this assumes you have a file named `src/variables.scss`
        data: `@import "@/styles/sassHelpers.scss";`
      }
    }
  }
}

2) Adding global styles only once by importing them into the root component. In App.vue style section:

<style lang="scss">
  @import "./styles/style";
...

The problem with Automatic imports that vue plugin offers us is that it is only for sass variables, colors and other sass helpers. It is not for styles.
Here what the Official documentation says:

If you want to automatically import files (for colors, variables, mixins... ), you can use the style-resources-loader.

It's not the solution and might be bad way to avoid importing global stylesheet in every component.
But I would like to share my way.

I created vue.js (using stylus) project via vue-cli 3.x.

I'm using reset-css file, global-css file and mixin variable file in my project.

The important thing, to avoid importing global stylesheet in every component, is using none-pre-compiled stylesheet file.

In my variables.styl

// * import node_modules stylesheet
@import '~reset-css/reset.css';

// * import global.css
@import './global.css'

// * stylus mixins
// 1. f_ for font
f_fam = 'Avenir', Helvetica, Arial, sans-serif
f_def = 14px
f_lg = 16px
f_sm = 12px
// 2. b_ for border
b_btm_1 = 1px #ebebeb solid
// 3. bg_ for background
bg_url = url('~/img/common/bg_sprites.png')

In my global.css

/* my global.css */
figure, figcaption {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
  overflow: hidden;
}

In my vue.config.js

const path = require('path')

module.exports = {
  chainWebpack: config => {
    const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
    types.forEach(type => addStyleResource(config.module.rule('stylus').oneOf(type)))
  }
}

function addStyleResource (rule) {
  rule.use('style-resource')
    .loader('style-resources-loader')
    .options({
      patterns: [
        path.resolve(__dirname, './src/assets/style/variables.styl'),
      ]
    })
}

then, you can import your global stylesheet just once.

2018-11-30 2 36 05

I would like to share that I find this part of the doc insufficient.

// you can also read from a file, e.g. variables.scss
data: $color: red;

It would be the very minimum to add a line for the typical path to a file containing globals. By typical, I mean "with the alias resolution" or with an import statement.

The better way would be to explain what is possible because I still don't get at all what is going on here.
If this is something from webpack, might as well add a link?

Looks like @kinoli and @Zver64 have the right idea. There's even an article here that covers how to do it for both vue-cli and non-vue-cli projects. Took all of 3 minutes to get this implemented in my project.

The only gotchas I ran into were the age-old syntax slip-ups. 🤦 (Don't forget that semicolon following your @import statements, kids!)

@kayoderock I have a link to that in this comment already.

@kayoderock I tried that solution it didn't work for me

I am getting this error

@ ./node_modules/vue-style-loader??ref--9-oneOf-1-0!./node_modules/css-loader??ref--9-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--9-oneOf-1-2!./node_modules/sass-loader/lib/loader.js??ref--9-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/index.vue?vue&type=style&index=0&lang=sass& 4:14-453 14:3-18:5 15:22-461

@kayoderock I tried that solution it didn't work for me

I am getting this error

@ ./node_modules/vue-style-loader??ref--9-oneOf-1-0!./node_modules/css-loader??ref--9-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--9-oneOf-1-2!./node_modules/sass-loader/lib/loader.js??ref--9-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/index.vue?vue&type=style&index=0&lang=sass& 4:14-453 14:3-18:5 15:22-461

Are you using Vue CLI 3

Yes @kayoderock, I am using Vue CLI 3

@mittalyashu Please, Do you have your vue.config.js file? and do you have the sass loader module?

Yes. I have both vue.config.js file and sass-loader and node-sass loader module

Here's the vue.config.js file

module.exports = {
    css: {
        loaderOptions: {
            sass: {
                data: `
                                         @import "@/assets/css/helpers/_helpers.sass";
                                `
            }
        }
    }
}

@mittalyashu Can I see the way you did your style in the index.vue file, Are you writing SCSS or SASS ?

Here is my solution to this issue. Has worked perfectly for me ever since. Uses the newest MiniCssExtractPlugin compatible with Webpack 4.

  • No CSS Duplication
  • No weird errors
  • PostCSS works flawlessly

Webpack Common

// Webpack 4
 ...
 module: {
    rules: [
      // CSS & SCSS Processing
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'sass-loader',
          {
            loader: 'sass-resources-loader',
            options: {
              // Load common SCSS [ Vars & Mixins ]
              resources: './src/assets/styles/shared.scss',
            },
          }
        ],
      },
  ...

App.vue

<template>
  <main id="app">
    <!-- Skip Navigatio Accessbility -->
    <button href="#mainContent"
      title="Skip to main content"
      aria-label="Skip to main content"
      v-on:click.stop.prevent="skipNav"
      class="mdev-skipnav" tabindex="0">
      Skip To Main Content
    </button>

    <main-navigation></main-navigation>
    <transition name="fade">
      <router-view></router-view>
    </transition>
  </main>
</template>




<script>

//Local Component registration
import MainNavigation from './components/shared/navigation.vue';

export default{

  components: {
    'main-navigation' : MainNavigation
  },

  methods: {
    skipNav() {
      var anchor = $("#mainContent").offset().top;
      $('html,body').scrollTop(anchor);
    }
  }
};
</script>



<style lang="scss">
// Loads global stylesheets (Excludes mixins and Vars loaded via sass-resources-loader)
@import './assets/styles/global-main.scss';

// Can add styles here referencing mixins or variables and it works!

</style>

@kayoderock A component file, looks something like this with SASS.

<template>
...
</template>

<script>
...
</script>

<style lang="sass">
 // Styles over here...
</style>

@mittalyashu I suspect you are writing SCSS in your style , while you stated the lang="sass", change it to lang="scss".

Let me know if this is the case else, I check out your error log again.

well i'm new to vue but i fix it very simple like the example below ;)

file structure

- ./src/App.vue
- ./src/views/About.vue
- ./src/scss/global.scss
- ./src/scss/variables.scss
- ./vue.config.js

App.vue

<style lang="scss">
@import "./scss/global.scss";
}

./scss/global.scss

@import "./scss/variables.scss";
@import "./scss/sassfile.scss";

./scss/variables.scss

$orange : orange;
$red : red;

./scss/_sassfile.scss
now all the links in my components or views have color orange

a{
    color: $orange;
}

for each one component or view you can override it
and make it own style only for each one using scoped
and it will assume that color RED only for that component or view

./views/About.vue

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
a {
  color: RED;
}
</style>

This way calling the scss var present in scss/variables.scss in the style of the component
it still not work so lets fix it this way

creating a vue.config.js in root project with this code

module.exports = {
  css: {
    loaderOptions: {
      // pass options to sass-loader
      sass: {
        // @/ is an alias to src/
        // so this assumes you have a file named `src/scss/variables.scss`
        data: `@import "@/scss/variables.scss";`
      }
    }
  }
}

Now you can use the sass vars in the style tag
./views/About.vue

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
a {
  color: $red;
}
</style>

i will leave here a copy of my package.json

{
"name": "vue-projectname",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"baseline": "^0.3.0",
"vue": "^2.5.22",
"vue-router": "^3.0.1",
"vuetify": "^1.5.1",
"vuex": "^3.0.1"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.4.0",
"@vue/cli-plugin-eslint": "^3.4.0",
"@vue/cli-service": "^3.4.0",
"@vue/eslint-config-standard": "^4.0.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.8.0",
"eslint-plugin-vue": "^5.0.0",
"node-sass": "^4.9.0",
"sass-loader": "^7.1.0",
"vue-template-compiler": "^2.5.21"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"@vue/standard"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
}

Don't want people to be able to use your components ? Just add sass in your .vue files...
Ever heard of Separation of Concerns ?

@golgote you are right. What I put in those files are general styles like application primary color etc

If you create your project with
vue init webpack prjName command.

you might solve this issues by change generateLoaders function on /build/utils.js like this
sass: generateLoaders('sass', { indentedSyntax: true, data: '@import "@/sass/vue-globals.scss";' }), scss: generateLoaders('sass', { data: '@import "@/sass/vue-globals.scss";'}),

/sass/vue-globals.scss

@import "@/sass/base/base_mixin.scss";
@import "@/sass/base/palette.scss";

I'm quite new for vueJS or webpack stuffs, I'm not sure it's right solution.
I tried alot of solutions above, but none them work for me.
except this one.(My own way)

I hope this helps someone :)

@kayoderock I guess my solution seems similar with your link, but More specifically work for vue init webpack prjName command.

vue init webpack prjName command create project with webpack.base.conf.js, webpack.dev.conf.js, webpack.prod.conf.js and that config files use generateLoaders function to setup style-loaders.

I just wrote that comment for less skilled persons like me :)

@ByungWookYe Alright, I get your point, I am just not sure if it's solving the problem here - having to load the sass at every needed point. Do you get me ?

@kayoderock yeah, It add @import "@/sass/vue-globals.scss"; for every sass codes or files ,just same as your linked solution, and thus it solved the problem.

Thats fine, @ByungWookYe it works too. Thanks.

I am trying to create a Vue Component Library, where all of the components have a default scss variable in them, for example:

$component-name-color: #000 !default

The intention is that the components will have default styling that could easily be configured/overridden when I later install my component library as an npm module in another project but be able to override the styles in a configurable variables scss file. I can't seem to figure out on how to have the vue library's config file to accept that scss file in order to apply the "overrides". Or, to update the end projects vue config file to merge with the vue component's config file.

I apologize if this should be a separate issue. I ultimately chose not to since it is mostly related to this issue.

Thanks @nellysattari
This worked for me: https://css-tricks.com/how-to-import-a-sass-file-into-every-vue-component-in-an-app/ Since I had simply missed the part about restarting the dev server from other examples, but she mentions that in this article.

Nuxt Style Resources module helps me.

I also implemented the vueschool solution. Everything is working fine, but I moved from @import to @use '~@/assets/scss/app';

The thing is that I can use variables like app.$theme-green etc. but Webstorm/Phpstorm can not resolve the namespace nor the variables and marks the namespace app as incorrect. However, the implementation is working but without autocompletion etc. it's just not as beautiful as a static import would be. Any ideas to fix this problem?

For those using the option 'data' of sass-loader, note that since v9.0.0 the option to specify the @import is now named additionalData.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

githoniel picture githoniel  ·  3Comments

NextSeason picture NextSeason  ·  3Comments

frangio picture frangio  ·  3Comments

sdvcrx picture sdvcrx  ·  3Comments

matt-sanders picture matt-sanders  ·  4Comments