Thursday, 10 September, 2020 UTC


Summary

To transpile .scss (or .sass) in Node you have the choice between sass and node-sass. sass is a JavaScript compilation of Dart Sass which is supposedly "the primary implementation of Sass" which is a pretty powerful statement. node-sass on the other hand is a wrapper on LibSass which is written in C++. Let's break it down a little bit more.

Speed

node-sass is faster. About 7 times faster. I took all the SCSS files behind the current MDN Web Docs which is fairly large. Transformed into CSS it becomes a ~180KB blob of CSS (92KB when optimized with csso).
Here's my ugly benchmark test which I run about 10 times like this:
node-sass took 101ms result 180kb 92kb node-sass took 99ms result 180kb 92kb node-sass took 99ms result 180kb 92kb node-sass took 100ms result 180kb 92kb node-sass took 100ms result 180kb 92kb node-sass took 103ms result 180kb 92kb node-sass took 102ms result 180kb 92kb node-sass took 113ms result 180kb 92kb node-sass took 100ms result 180kb 92kb node-sass took 101ms result 180kb 92kb
And here's the same thing for sass:
sass took 751ms result 173kb 92kb sass took 728ms result 173kb 92kb sass took 728ms result 173kb 92kb sass took 798ms result 173kb 92kb sass took 854ms result 173kb 92kb sass took 726ms result 173kb 92kb sass took 727ms result 173kb 92kb sass took 782ms result 173kb 92kb sass took 834ms result 173kb 92kb
In another example, I ran sass and node-sass on ./node_modules/bootstrap/scss/bootstrap.scss (version 5.0.0-alpha1) and the results are after 5 runs:
node-sass took 269ms result 176kb 139kb node-sass took 260ms result 176kb 139kb node-sass took 288ms result 176kb 139kb node-sass took 261ms result 176kb 139kb node-sass took 260ms result 176kb 139kb
versus
sass took 1423ms result 176kb 139kb sass took 1350ms result 176kb 139kb sass took 1338ms result 176kb 139kb sass took 1368ms result 176kb 139kb sass took 1467ms result 176kb 139kb

Output

The unminified CSS difference primarily in the indentation. But you minify both outputs and the pretty print them (with prettier) you get the following difference:
▶ diff /tmp/sass.min.css.pretty /tmp/node-sass.min.css.pretty 152c152 < letter-spacing: -0.0027777778rem; --- > letter-spacing: -0.00278rem; 231c231 < content: "▼︎"; --- > content: "\25BC\FE0E"; ...snip... 2804c2812 < .external-icon:not([href^="https://mdn.mozillademos.org"]):not(.ignore-external) { --- > .external-icon:not([href^='https://mdn.mozillademos.org']):not(.ignore-external) { 
Basically, sass will use produce things like letter-spacing: -0.0027777778rem; and content: "▼︎";. And node-sass will produce letter-spacing: -0.00278rem; and content: "\25BC\FE0E";.
I also noticed some minor difference just in the order of some selectors but when I look more carefully, they're immaterial order differences meaning they're not cascading each other in any way.
Note! I don't know why the use of ' and " is different or if it matters. I don't know know why prettier (version 2.1.1) didn't pick one over the other consistently.

node_modules

Here's how I created two projects to compare
cd /tmp mkdir just-sass && cd just-sass && yarn init -y && time yarn add sass && cd .. mkdir just-node-sass && cd just-node-sass && yarn init -y && time yarn add node-sass && cd .. 
Considering that sass is just a JavaScript compilation of a Dart program, all you get is basically a 3.6MB node_modules/sass/sass.dart.js file.
The /tmp/just-sass/node_modules directory is only 113 files and folders weighing a total of 4.1MB.
Whereas /tmp/just-node-sass/node_modules directory is 3,658 files and folders weighing a total of 15.2MB.
I don't know about you but I'm very skeptical that node-gyp ever works. Who even has Python 2.7 installed anymore? Being able to avoid node-gyp seems like a win for sass.

Conclusion

The speed difference may or may not matter. If you're only doing it once, who cares about a couple of hundred milliseconds. But if you're forced to have to wait 1.4 seconds on every Ctrl-S when Webpack or whatever tooling you have starts up sass it might become very painful.
I don't know much about the sass-loader Webpack plugin but it apparently works with either but they do recommend sass in their documentation. And it's the default implementation too.
It's definitely a feather in sass's hat that Dart Sass is the "primary implementation" of Sass. That just has a nice feelin in sass's favor.

Bonus

NPMCompare has a nice comparison of them as projects but you have to study each row of numbers because it's rarely as simple as more (or less) number is better. For example, the number of open issues isn't a measure of bugs.
The new module system launched in October 2019 supposedly only comes to Dart Sass which means sass is definitely going to get it first. If that stuff matters to you. For example, true, the Sass unit-testing tool, now requires Dart Sass and drops support for node-sass.