tony19 tony19 - 4 years ago 198
Sass (Sass) Question

How do I escape native CSS mixins in Sass without string wrapper?

NOTE: I don't think this is a duplicate of Ignore parts of sass file for parsing because I'm looking for an alternative that doesn't require wrapping the native mixin in a string, which is the only solution presented in the other question.




Sass is converting this native CSS mixin:

// my-view1.scss
my-view1 {
--view1-card: {
border: solid 1px blue;
opacity: 0.5;
};
}


into:

// my-view1.css
my-view1 {
--view1-card-border: solid 1px blue;
--view1-card-opacity: 0.5;
}


But I want it passed through. To prevent the unwanted conversion, I'm using Sass string interpolation
#{'...'}
:

// my-view1.scss
my-view1 {
--view1-card: #{'{
border: solid 1px blue;
opacity: 0.5;
}'};
}


But this defeats the IDE's IntelliSense and syntax highlighting. What are my alternatives that wouldn't require stuffing the CSS mixin in a string?

related GitHub issue

Answer Source

TLDR: To me, the best solution was to switch to dart-sass 1.0.0-alpha.8, which correctly parses native CSS mixins.


Option 1: Pre-parse before feeding to Sass

I could update my Gulp task to preparse the file for native CSS mixins, and wrap them in Sass string interpolation before passing the output to Sass. For example, given this input:

$color: blue;
--view1-card: {
  color: #{$color};
};

The preparser would produce this output:

$color: blue;
--view1-card: #{'{
  color: #{$color};
}'};

This could be easily acheived with String#replace (or gulp-replace), using the right regular expression, like this:

sassInput.replace(/(--[-\w]+:\s*)(\{[\s\S]*\})/gm, "$1#{'$2'}");

Option 2: Use bleeding edge sass/libsass

This issue is fixed in the bleeding edge 3.5 or 4.0 builds of sass or libsass. In my case, I'm using gulp-sass, which uses node-sass, which wraps libsass. To get this fix in my Gulp build, I would:

  1. Fork the GitHub repos for gulp-sass and node-sass.
  2. Update node-sass dependency on libsass so that it uses the commit/branch, containing the fix.
  3. Check in the node-sass change on a branch.
  4. Update gulp-sass dependency to point to that node-sass branch.
  5. Check in the gulp-sass change on a branch.
  6. Update my project's dependency to use that gulp-sass branch.

A lot of extra work here, but it could be worth the trouble as several interesting features were added in the newest builds.

Option 3: Use dart-sass

This issue is not present in dart-sass 1.0.0-alpha.8. I could update my build to use it instead of gulp-sass. (I could also update gulp-sass to use dart-sass with the steps above for bleeding-edge libsass, but I went with direct usage of dart-sass.)

I had to wrap dart-sass with through2 like this:

const dartSassPipe: Transform = through2.obj((file, _enc, cb) => {
  dartSass.render({file: file.path}, (err: Error, result: Buffer) => {
    if (err) {
      console.error(chalk.red('[dart-sass] ') + err.message);
    } else {
      file.contents = result.buffer;
    }
    cb(err, file);
  });
});

This pipe replaces the stream's contents with Sass output, but I also need the stream's file extension to change from .scss to .css, so I used gulp-ext-replace.

This allowed me to replace gulp-sass in my Gulp stream like this:

  const stream = pump([
    gulp.src('src/**/*.{css,sass,scss}'),
-    $.sass().on('error', $.sass.logError),
+    dartSassPipe,
+    $.extReplace('.css'),
    gulp.dest(distDir),
  ]);
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download