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

Pass variables to scss files #49

Closed
nwhite89 opened this issue Feb 9, 2015 · 56 comments
Closed

Pass variables to scss files #49

nwhite89 opened this issue Feb 9, 2015 · 56 comments

Comments

@nwhite89
Copy link

nwhite89 commented Feb 9, 2015

I'm wanting to pass variables from webpack to the scss files, for example opacity is able to be changed by a user and stored in the db. Ideally I'd pass the variable same way as you do to JS files via webpack and pass them straight through to the SCSS files before compilation.

@jhnns
Copy link
Member

jhnns commented Feb 10, 2015

Could you show an example how you'd expect things to work?

I'm afraid that this is currently not possible (if I got it right). But with custom importers #31 it's probably possible. Then you can write a special loader, which generates scss code to import your dynamic vars.

@nwhite89
Copy link
Author

@jhnns thank you for your response I'm thinking of the webpack.DefinePlugin so perhaps something like

webpack.DefinePlugin({
  'SCSS_OPACITY': '0.4'
});
$opacity: SCSS_OPACITY;
@include opacity($opacity);

but perhaps if it's easier for it to create a file with all of them and somehow matching SCSS_OPACITY to be $SCSS_OPACITY ?? and attaching the variables above of files when generating? what are your thoughts?

@jhnns
Copy link
Member

jhnns commented Feb 10, 2015

Mhmmm your solution would probably work too.

And when you need to access the variables also via client-side JavaScript:

webpack.DefinePlugin(require("./styles/variables.js"));

@nwhite89
Copy link
Author

Yeah, using the definePlugin I think would be ideal because it would use the current inner workings of webpack but also allow for variables to be used across both the JS and SCSS files which I'm not entirely sure when you may need it but it would be more powerful I feel.

@jhnns
Copy link
Member

jhnns commented Feb 11, 2015

Oh, there are use-cases where this is required... :)

I'll check that!

@nwhite89
Copy link
Author

Using this perhaps? https://github.com/webpack/docs/wiki/list-of-plugins#dependency-injection

Without looking into it I would hazard a guess it should make it easier? (hopefully) :)

@kasper573
Copy link

Hi! I wanted the same feature a while back but realized this is already supported by webpack. My solution looks like this:

var sass = encodeURIComponent(jsonToSassVars(sassGlobals));
var webpackConfig = {
    module: {
        loaders:[
            {test: /.scss$/, loader: "style!css!sass!prepend?data=" + sass}
        ]
    },
}

The prepend-loader and jsonToSassVars are custom work of mine.

@nwhite89
Copy link
Author

nwhite89 commented Apr 7, 2015

@kasu any chance of them being made Open Source?

@kasper573
Copy link

@nwhite89 Sure thing, here you go: prependLoader.js and jsonToSassVars.js.

@nwhite89
Copy link
Author

nwhite89 commented Apr 8, 2015

@kasu cheers 👍 although it would be nice to have this functionality baked into sass-loader

@jhnns
Copy link
Member

jhnns commented Apr 10, 2015

@kasu haha, nice!
@nwhite89 no I don't think so. I don't want to extend the language itself...

@EdwardIrby
Copy link

@kasu really liked your work so I went and forked it into a npm loader https://www.npmjs.com/package/jsontosass-loader

@nwhite89
Copy link
Author

@EdwardIrby 👍

@kasper573
Copy link

@EdwardIrby cool :)!

@jhnns
Copy link
Member

jhnns commented Oct 5, 2015

Is @EdwardIrby 's solution working for you? I'd like to link the loader in our README, but I'm not sure about how safe that string replaces are 😁 ...

Do you have any experience on this?

@wendellmva
Copy link

@EdwardIrby I don't think you should return a json file but a js file that returns an json object. This way you can do custom calculations to darken or lighten a color for example or other caculations you might need.

@nightgrey
Copy link

@nwhite89 @EdwardIrby @jhnns I think this could be what you guys need: Sassport

I just found this myself and didn't use it yet, but it seems like it enables you to do what you want - sharing values between JavaScript and Sass.

@jhnns
Copy link
Member

jhnns commented Apr 3, 2016

Thx @nightgrey

This issue can now also be solved with the data-option. Just define any Sass code which will be prepended to the actual entry file.

@matt-newell
Copy link

matt-newell commented May 11, 2016

@jhnns can we see a working example of the data option? Having issues getting it to work

Never mind looking back at earlier PR's I found my query params were overriding my sassLoader. It's a bit confusing where to options, query params or sassLoader

@jhnns
Copy link
Member

jhnns commented May 12, 2016

It's a bit confusing where to options, query params or sassLoader

I know... this will be simpler with webpack 2 where there is a dedicated way to set the options (query params didn't work so well with more complex use-cases).

@mwilc0x
Copy link

mwilc0x commented Jun 15, 2016

@jhnns I can get the environment variable to be passed in via data-option and I see that it is working in the app.

I am doing something like:

sassLoader: {
  data: '$myColor: green;',
},

and then in a random .scss file I just use color: $myColor. It works, I can see the color appearing in the application, but I am also seeing errors at compile time: Undefined variable: "$myColor". Is there a step that I am missing here to complete this so as to not get those errors?

@jhnns
Copy link
Member

jhnns commented Jun 15, 2016

Nope, looks good. There must be a different error in your setup.

@mwilc0x
Copy link

mwilc0x commented Jun 17, 2016

@jhnns Yeah, the issue was that I wasn't including this option on the server bundle as well. It is working, thanks!

@dsc8x
Copy link

dsc8x commented Sep 2, 2016

Hey guys, had the same needs for passing vars to my sass files, so i also created a little webpack loader based on @kasu's gist. It lets you import vars directly via webpack, or by specifying a JSON or JS file. Check it out :)

@Cleod9
Copy link

Cleod9 commented Sep 2, 2016

After much digging around, I found an even easier solution:

https://www.npmjs.com/package/webpack-append

Despite its misleading name, this package does, in fact, prepend specified text to the beginning of each file. And unlike prepend-loader, it doesn't have any issues with style-loader 😄

@dsc8x
Copy link

dsc8x commented Sep 2, 2016

How is that easier than passing the vars directly in webpack config or by specifying paths to JS/JSON files?
https://github.com/epegzz/sass-vars-loader does support exactly that:

// webpack.js
sassVars: {
  vars: {
    someColor: red,
    someOtherColor: blue,
   }
 }

…and you're ready to use them anywhere in your scss

.foo {
  color: $someColor;
}

@Cleod9
Copy link

Cleod9 commented Sep 2, 2016

@epegzz This way you can basically just write Sass rather than JS. Also by prepending as a string you could theoretically just use fs to prepend a full .scss file if you wanted. To give you some context, the earlier answer of prepend-loader sufficed for me for a time, but broke after I had switched from ExtractTextPlugin to style-loader

@dsc8x
Copy link

dsc8x commented Sep 2, 2016

@Cleod9 writing JS or JSON inside the webpack config which is JS itself feels way nicer to me. And the OP wanted to pass data potentially stored in a database. Chances are, those data already come as JSON or even JS object when he's loading them inside the webpack.js. But in the end, it's all a matter of personal preference and specific use case :)

@Cleod9
Copy link

Cleod9 commented Sep 2, 2016

@epegzz True, and I appreciate your plugin btw! I think for others who land in this thread will find that at least one of these solutions will work for them (this thread is like the number one search result for "sass variables through webpack" 😉 )

@IAMtheIAM
Copy link

@epegzz is it webpack2 compatible? Webpack2 doesn't allow custom properties on the webpack config, must use the LoaderOptionsPlugin for any custom properties.

@dsc8x
Copy link

dsc8x commented Sep 22, 2016

@IAMtheIAM haven't tested yet, but no, probably not then, thx for pointing it out! :)

The following should work with webpack2 though, right?

// webpack.js
var sassVarsConfig = querystring.stringify({
    files: [
        path.resolve(__dirname, 'path/to/vars.js'),
    ]
});

return {
    loader: ExtractTextPlugin.extract(
        'style',
        'css!sass!@epegzz/sass-vars-loader?' + sassVarsConfig
    ),
  //...

@IAMtheIAM
Copy link

IAMtheIAM commented Sep 23, 2016

@epegzz Good job dude! That worked perfectly, thanks, I was struggling for hours to get any of these options to work with webpack 2, so that I can take a JS/JSON file and have it converted to sass, and appended before all scss files. Great!

Here's my full setup:

// webpack.config.js

var sassVarsConfig = querystring.stringify({
   files: [
      path.resolve(helpers.paths.appRoot + '/assets/styles/sass-js-variables.js'),
   ]
});

// loaders section
         {
            test: /\.(scss)$/,
            loaders: DEBUG ?
               ['style', 'css?sourceMap', 'postcss', 'sass?sourceMap', 'sass-resources', '@epegzz/sass-vars-loader?' + sassVarsConfig] : // dev mode
               ExtractTextPlugin.extract({
                  fallbackLoader: "sass-loader",
                  notExtractLoader: "sass-loader",
                  loader: ['css?sourceMap', 'postcss', 'sass?sourceMap', 'sass-resources','@epegzz/sass-vars-loader?' + sassVarsConfig],
                  publicPath: '/' // 'string' override the publicPath setting for this loader
               })
         },

//plugins section

      new webpack.LoaderOptionsPlugin({
         options: {
            sassResources: ['./src/assets/styles/variables.scss', './src/assets/styles/mixins.scss'],
            context: helpers.paths.root
         }
      }),

      new ExtractTextPlugin({
         filename: '/css/[name].style.css?[hash]',
         disable: false,
         allChunks: true
      }),
// sass-js-variables.js

module.exports = {
   primary: '#C0FF33',
   secondary: '#B4D455'
};
// home.scss

ticket {
   color: $primary;
   .card-panel {
      background-color: $secondary;
   }
}

Now the only thing I'm wondering is it your sass-vars-loader can replace the functionality of the sass-resources-loader? Basically it just appends an array of .scss files to the beginning of each .scss file loaded, which I use for passing all my variables and mixins to my scss files. Can your loader do that, and if so, what's the proper way? It's not a big deal, since it works as is, I can use 2 loaders if necessary.

@IAMtheIAM
Copy link

IAMtheIAM commented Sep 26, 2016

@epegzz I made a pull request fixing your loader, to allow users to pass "vars" directly on the webpack config, rather than in an external file. So now both options work. Please review and approve it so others can use :-)

You just have to JSON.stringify anything in the vars property like this:

const susyDebug = DEBUG ? 'show' : 'hide';
const sassVarsConfig = querystring.stringify({
   files: [
      path.resolve(helpers.paths.appRoot + '/styles/sass-js-variables.js')
      // path.resolve(__dirname, '/path/to/breakpoints.js'), // JS
      // path.resolve(__dirname, '/path/to/colors.json'), // JSON
   ],
   vars: [JSON.stringify({'susyDebug': susyDebug})],
});

Then, your loader should look something like:

loaders: ['css?sourceMap', 'postcss', 'sass?sourceMap', '@epegzz/sass-vars-loader?' + sassVarsConfig],

@dsc8x
Copy link

dsc8x commented Sep 27, 2016

awesome @IAMtheIAM, merged and pushed to npm :)

@534N
Copy link

534N commented Sep 28, 2016

@epegzz I can't install your module:

npm ERR! Invalid name: "@epegzz/sass-vars-loader"

@dsc8x
Copy link

dsc8x commented Sep 28, 2016

@534N I answered in dsc8x/sass-vars-loader#6 :)

@nagarajay
Copy link

@jhnns Is the data option working correctly for Webpack V2. @epegzz @IAMtheIAM great solution. I will try to use it as stated.

@jhnns
Copy link
Member

jhnns commented Oct 20, 2016

@nagarajay Does this work for you?

@mkarajohn
Copy link

mkarajohn commented Oct 21, 2016

I understand that the solutions above allow us to define and use SASS variables in our sass files without actually touching them, but how about overriding existing variables?

For example, could we override the $enable-flex variable of Bootstrap 4 from false to true in order to build the flexbox version of the grid ?

@jhnns
Copy link
Member

jhnns commented Oct 21, 2016

When they're using !default, yes. Otherwise, no.

@CodePlayer7
Copy link

CodePlayer7 commented Dec 20, 2016

With using "sass-loader": "4.0.2","webpack": "^1.13.2",, it comes to me that the environment variable function doesn't work.Compiling throws error Undefined variable

@JasonEtco
Copy link

JasonEtco commented Feb 9, 2017

I think it's worth noting that @jhnns above solution is great, but the description on how to actually use it wasn't clear. The sassLoader object has to be in the root of your webpack's exported object, like this:

module.exports = {
  entry: [...],
  module: {
    loaders: [...],
  },
  sassLoader: {
    data: '@import "variables";',
    includePaths: [
      path.resolve(__dirname, '../src/scss/tools'),
    ],
  },
};

@jhnns
Copy link
Member

jhnns commented Feb 9, 2017

While this is true for webpack 1, this has been changed with webpack 2. See current README.

@jhnns jhnns closed this as completed Feb 9, 2017
@volodymyr-tsaryk
Copy link

@CallMeXYZ did you resolve your issue ? I am having same

@CodePlayer7
Copy link

@volodymyr-tsaryk check above @jhnns answers. For simple varibles you may do sth like this

{
    loader: "sass-loader",
    options: {
        data: "$var1: " + yourVar1+ ";"
    }
}

@volodymyr-tsaryk
Copy link

@CallMeXYZ that worked, thanks

@scott-thrillist
Copy link

So useful, glad Google led me here. Thanks all.

https://webpack.js.org/loaders/sass-loader/#environment-variables

@scorgn
Copy link

scorgn commented Jun 4, 2018

@epegzz Your solution is great, although I'm wondering if there's a way to use it when requiring scss files. I think that it would make more sense to be able to specify the variables in your index.js file.

The reason I want to do this is I would like to be able to set background-images dynamically. Something like

var headerBackgroundImage = require(htmlWebpackPlguin.options.bgImage);
require('style.scss')({
    '$header-background': headerBackgroundImage
});

@dsc8x
Copy link

dsc8x commented Jun 9, 2018

@ShawnCorrigan although I can see use-cases for your proposal, it, unfortunately, does not play well with ES6 modules :(

@dsc8x
Copy link

dsc8x commented Jun 9, 2018

@ShawnCorrigan However, you could simply call require(htmlWebpackPlguin.options.bgImage) in your webpack config file:

// webpack.config.js

const headerBackgroundImage = require(htmlWebpackPlguin.options.bgImage);

module.exports = {
  module: {
    rules: [{
      test: /\.scss$/,
      use: [
        // …
        { 
          loader: "@epegzz/sass-vars-loader",
          options: {
            vars: {
              'header-background': headerBackgroundImage
            }
          }
        }
      ]
    }]
  },
};

@scorgn
Copy link

scorgn commented Jun 9, 2018

@epegzz Hmm okay. The idea was to not really modify the webpack.config.js file, although I suppose I could have another file that the webpack.config.js file uses to load the images. Thanks for the response!

@dsc8x
Copy link

dsc8x commented Jul 7, 2018

@ShawnCorrigan Sorry for the late reply, I somehow missed your response above.

But yeah, you're absolutely right. In most cases, you probably want to load all vars from a file and never touch the Webpack config again :)

@BruneXX
Copy link

BruneXX commented Nov 23, 2018

Hi @volodymyr-tsaryk with one var works like a charm, but how to share multiple vars? is that possible? thanks!

@devtas
Copy link

devtas commented Apr 5, 2019

@kasu really liked your work so I went and forked it into a npm loader https://www.npmjs.com/package/jsontosass-loader

This guy no longer supports this lib. Sad.

@subvertallchris
Copy link

Anyone trying to use simple variables as described by above, the data key appears to have been changed to prependData. You'd now do this:

{
    loader: "sass-loader",
    options: {
        prependData: "$var1: " + yourVar1+ ";"
    }
}

@boltgolt
Copy link

boltgolt commented Nov 8, 2022

If you're here through a google search, this has been renamed once more to additionalData, so:

{
	loader: "sass-loader",
	options: {
		additionalData: '$myColor: green;'
	}
}

See #865

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