Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load a global settings.scss file in every vue component? #328

Closed
westwick opened this issue Aug 26, 2016 · 155 comments
Closed

Load a global settings.scss file in every vue component? #328

westwick opened this issue Aug 26, 2016 · 155 comments

Comments

@westwick
Copy link

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.

@lessYFF
Copy link

lessYFF commented Sep 9, 2016

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

@ericcirone
Copy link

I basically have the same question as well.

@sqal
Copy link

sqal commented Sep 21, 2016

@westwick have you tried - https://github.com/shakacode/sass-resources-loader

@jbruni
Copy link

jbruni commented Sep 23, 2016

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

@ericcirone
Copy link

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.

@LinusBorg
Copy link
Member

LinusBorg commented Sep 23, 2016

@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! 👍

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!
    }
  }
}

@ericcirone
Copy link

@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.

@gregorskii
Copy link

@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.

@LinusBorg
Copy link
Member

Clsoing as this issue seems to be solved.

@uptownhr
Copy link

uptownhr commented Dec 8, 2016

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.

@westwick
Copy link
Author

westwick commented Dec 8, 2016

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

@LinusBorg
Copy link
Member

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.

@LinusBorg
Copy link
Member

@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.

@jpt
Copy link

jpt commented Dec 11, 2016

@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.

@LinusBorg
Copy link
Member

LinusBorg commented Dec 11, 2016

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.

@kidBrazil
Copy link

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?

@LinusBorg
Copy link
Member

LinusBorg commented Dec 22, 2016

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.

@westwick
Copy link
Author

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.

@LinusBorg
Copy link
Member

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.

@westwick
Copy link
Author

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.

@LinusBorg
Copy link
Member

Great :)

@uptownhr
Copy link

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?

@LinusBorg
Copy link
Member

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 ..)

@delucis
Copy link

delucis commented Jan 1, 2017

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!

@LinusBorg LinusBorg reopened this Jan 1, 2017
@LinusBorg
Copy link
Member

@import "~styles/_vars.scss";

@Jack-Barry
Copy link

Jack-Barry commented Dec 15, 2018

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
Copy link

I feel the best solution I have seen is this:
https://vueschool.io/articles/vuejs-tutorials/globally-load-sass-into-your-vue-js-applications/

@mittalyashu
Copy link

@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
Copy link

@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

@mittalyashu
Copy link

Yes @kayoderock, I am using Vue CLI 3

@kayoderock
Copy link

kayoderock commented Jan 30, 2019

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

@mittalyashu
Copy link

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";
                                `
			}
		}
	}
}

@kayoderock
Copy link

kayoderock commented Jan 30, 2019

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

@kidBrazil
Copy link

kidBrazil commented Jan 30, 2019

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>

@mittalyashu
Copy link

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

<template>
...
</template>

<script>
...
</script>

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

@kayoderock
Copy link

@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.

@lucho20pt
Copy link

lucho20pt commented Feb 18, 2019

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"
]
}

@golgote
Copy link

golgote commented Feb 24, 2019

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

@kayoderock
Copy link

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

@nellysattari
Copy link

That also combined some solutions in one post:
https://css-tricks.com/how-to-import-a-sass-file-into-every-vue-component-in-an-app/

@ByungWookYe
Copy link

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
Copy link

@ByungWookYe
Copy link

ByungWookYe commented Mar 7, 2019

@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 :)

@kayoderock
Copy link

@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 ?

@ByungWookYe
Copy link

@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.

@kayoderock
Copy link

Thats fine, @ByungWookYe it works too. Thanks.

@Secular12
Copy link

Secular12 commented Mar 10, 2019

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.

@jordanboston
Copy link

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.

@nick-dolan
Copy link

Nuxt Style Resources module helps me.

BugKun pushed a commit to BugKun/mpvue-loader that referenced this issue Jun 1, 2020
* update docs for global scss loading

per this comment thread: vuejs/vue-loader#328 (comment)

* be more generic about webpack rule

* update text
@Exotelis
Copy link

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?

@cgodo
Copy link

cgodo commented Apr 14, 2021

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.

@Shist
Copy link

Shist commented Jun 24, 2024

For the next project structure:
image
This instruction inside vue.config.js helped me to connect all the styles globally (not needed to include per each component separately):

const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
  transpileDependencies: true,
  css: {
    loaderOptions: {
      sass: {
        additionalData: `
          @import "@/assets/styles/global";
        `,
      },
    },
  },
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests