Eric
Eric

Reputation: 5215

Gulp - want to inject SCSS variable into another file

UPDATE -- See additional info below, added on 22 March...

I want to inject an SCSS variable into a code file with my Gulp process.

I think this is two steps:

  1. Gulp the SCSS _variables.scss file so I can access the variable

  2. Just do a simple gulp.replace to do a string-replace and drop the variable value into my file (like the answer here)

I'm stuck on step 1. Here's what I have... as best I can tell, the not-heavily-documented gulp-sass-variables plugin is supposed to pull the variables from the SCSS file into the argv object. So I followed the example on that plugin page, and tried this:

gulp.task('test', function () {
    gulp.src('sass/*')
        .pipe(plugins.print())
        .pipe(plugins.sassVariables({
            $foundIt: argv.testSassVar
        }))

    console.log(argv);

});

The print() call is just to confirm that it is reading my SCSS files (and it is). But it can't find $testSassVar in my SCSS code, as you can see from this error message:

[12:53:04] Using gulpfile ~/dev/project/gulpfile.js
[12:53:04] Starting 'test'...
[12:53:04] 'test' errored after 15 ms
[12:53:04] ReferenceError: testSassVar is not defined
    at Gulp.<anonymous> (...)
[12:53:04] sass/_mixins.scss        <- this line and all below are from print()
[12:53:04] sass/_normalize.scss
[12:53:04] sass/_variables.scss
[12:53:04] sass/footer
[12:53:04] sass/header
[12:53:04] sass/landing
[12:53:04] sass/landing-style.scss
[12:53:04] sass/site
[12:53:04] sass/style.scss

I tried removing that $foundIt assignment, and just trying to fill the argv object, but that ends up outputting an empty array:

[13:00:57] Using gulpfile ~/dev/project/gulpfile.js
[13:00:57] Starting 'test'...
{ _: [ 'test' ], '$0': 'gulp' }
[13:00:57] Finished 'test' after 41 ms

Any ideas how I can accomplish what I'm trying to do?!


EDIT 22 March

Looks like I can partially accomplish this by going a different route and using the gulp-sass-json plugin:

gulp.task('sass-json', function () {
    return gulp
        .src(scss_base + '*')
        .pipe(plugins.sassJson())
        .pipe(gulp.dest(tmp + 'sass-vars.json'));
});

This writes a file to /tmp with my SCSS variables compiled into a JSON file. Then I thought, ok, I can load the JSON file in gulp and parse it from there. Unfortunately, this plugin doesn't resolve 2nd level variables (i.e. variables that reference variables), so you get something like this:

 {
     # variables parsed from SCSS to JSON by gulp-sass-json

     # these are ok
     "font__main": "'Open Sans', sans-serif",
     "font__heading": "'Open Sans', sans-serif",
     "font__line-height-body": "1.5",
     "testSassVar": "123",
     "color__nbar": "#ffffff",
     "color__nbar_bg": "#50B107",
     "size_border-radius": "3px"

     # these variables reference other variables, not parsed, ouch
     "color__background-body": "$color__nbar",
     "color__background-screen": "$color__nbar",

     # and this is even worse, the SCSS function isn't parsed, double ouch
     "color_test": "lighten($color__nbar, 50%)",
 }

As you can see, the variables that are simple references to other variables could probably be fixed with a bit of Javascript to just parse them, but once you get into the SASS functions, that idea falls apart.

Ideally, the SCSS compiler could parse and variables that aren't static values. Is that possible (or is that starting to really get into the weeds to solve this problem)?

The only other thought I had was to move all my variables to a JSON file, then use a gulp plugin that moved in the other direction -- JSON to SASS variables. But then I wouldn't get the advantage of having the SCSS compiler to run functions, parse variables, etc, and then give those values back to my gulp file.

Since my goal is to have the SASS values in the (parsed) variables available to my gulp file, so I can turn around and drop them into another (HTML or PHP) code file doing a simple string replace. If there's an easier way to accomplish my final goal, I'm all ears...

Upvotes: 0

Views: 2146

Answers (3)

young-ceo
young-ceo

Reputation: 5374

Here is my solution - you need to have gulp-inject

main.scss file

...
/* inject:scss */
/* endinject */
...

gulpfile.js file

var gulpInject = require('gulp-inject');

...

gulp.src('...your/main/scss/file.scss')
.pipe(
    gulpInject(gulp.src('...your/partial/scss/**/*.scss'), {
        relative: true,
        transform: function (filePath) {
            var fileWithoutExtension = filePath.replace('.scss', '');
            return '@import \'' + fileWithoutExtension + '\';';
        }
    })
)
.pipe(...)
...

The above example will inject partial SCSS files into the main SCSS file.

Hopefully my code would be helpful.

Upvotes: 0

jgranstrom
jgranstrom

Reputation: 586

I've also authored a library for this kind of use case that uses native sass compiler feature to extract the variable values called sass-extract which also comes with a webpack loader and babel plugin depending on the use case.

The benefit is that is based on the native sass type system and thus supports all kinds of sass features like functions, mixins, lists, maps etc. It also handles imports, overrides, defaults etc as expected.

If you are open to using webpack you can simply import the sass file:

const style = require('sass-extract-loader!./style.scss'); 

to get the variables extracted, which would be the easiest option. Otherwise you can just use the core library directly as such:

const sassExtract = require('sass-extract');

sassExtract.render({
  file: 'path/to/my/styles.scss'
})
.then(rendered => {
  console.log(rendered.vars);
});

There is also a synchronous version available that you can use to integrate with your gulp pipelines.

Upvotes: 1

Enoah Netzach
Enoah Netzach

Reputation: 777

I recently had a similar issue, although I'm not using gulp.

I searched for npm packages that could accomplish this task (variable extraction from SCSS), but the couple I found were subpar.

So, I ended up writing my own lib (extract-scss-variables). We use it in production, it's tested against foundation and a couple of other common uses.

I sincerely don't remember how to produce a gulp plugin anymore, but this library in itself shouldn't be hard to integrate.

In your specific case I'd do something like:

var extractScssVariables = require('extract-scss-variables');
var variables = extractScssVariables({
  entryPoint: 'path/to/sass/style.scss',
  files: [
    'path/to/sass/_mixins.scss',
    'path/to/sass/_normalize.scss',
    'path/to/sass/_variables.scss',
  ],
  sassOptions: { 
    includePaths: ['path/to/libraries/to/include.scss'],
  },
});

where the entryPoint is the context where the variables are extracted (e.g. if you overwrite a variable declared in _mixins.scss, the entryPoint's one is used instead);
files is the array of files where to extract SCSS variables from;
and sassOptions are any command line sass options you are already using.

Upvotes: 1

Related Questions