Support building scss with sass-embedded
Command
build, serve
Description
Over the last year the sass-embedded package has become really stable and is much faster than the sass package used by the angular CLI for building scss files today (on our enormous application, we were able to compile all our scss files about 30s faster using sass-embedded)
Vite also recently added support: https://github.com/vitejs/vite/pull/17754
Describe the solution you'd like
If the sass-embedded embedded package is installed in the root package.json, the angular CLI would use that to compile all scss files instead of the sass package.
Describe alternatives you've considered
No response
This is definitely worth revisiting. When we ran benchmarks previously, we noticed it was significantly faster with large SCSS files. However, for smaller stylesheets, the overhead introduced by spawning an additional child process for each sheet caused compilation to take longer—especially for component styles, which are typically smaller.
We should give this another go and run benchmarks again.
I'm sorry if I grossly underestimate the size of your codebase, however, we could greatly increase sass performance by not importing massive amount of files (like variables and mixins) in every single component. We still have a shared import on top of each scss, but that is only allowed to be all the variables and the 3 most used mixins. Every other mixin must me imported explicitly when required. This way we changed the scss build burden from being a serious bottleneck (being ~30% of the build time) to being barely noticeable.
If I read sass-embedded correctly, it's still dart sass under the hood. Just a layer on top that allows concurrency faked behind a synchronous api. So my guess is, that sass-embedded will not be faster if your build already maxes out all your cpu cores, as angular is already quite concurrent. But I could be wrong.
If I read sass-embedded correctly, it's still dart sass under the hood.
@sod Yes, and no. It is generated from the same Dart Sass codebase, but it's a native build. sass is Dart transpiled to JavaScript; as with any transpilation, the code may be huge and/or ineffective. Also, it's still JavaScript, so we only benefit from JIT. sass-embedded compiles Dart Sass into native binaries.
So my guess is, that sass-embedded will not be faster if your build already maxes out all your cpu cores, as angular is already quite concurrent.
I ran some tests. I first compared sass to sass-embedded while compiling just the Bootstrap:
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
sass |
645.2 ± 3.4 | 641.5 | 651.4 | 3.04 ± 0.03 |
sass-embedded |
212.3 ± 1.8 | 209.8 | 214.9 | 1.00 |
sass-embedded is three times quicker, even on sub-second compilations. But it's just the styles!
So, I have tried it on a big work project. I took a copy of @angular-devkit/build-angular, replaced imports with sass-embedded and replaced the dependency.
| Sass | First run | Second run |
|---|---|---|
sass |
57.3 | 20.1 |
sass-embedded |
54.7 | 19.6 |
So, yes, using sass-embedded seems to offer negligible speed-up for large projects. Take this with a grain of salt, though, as this is using Webpack and not esbuild, so lots of time is probably spent on JS bundling.
Of course, my comment does not prove (nor disprove) anything. There are simply too many different Angular projects and configurations in the wild. I'd propose we handle it like Webpack sass-loader already does: Make Sass a peer dependency and let the user choose whatever suits their taste and workflow.
Hello guys, want to share our numbers to keep this issue alive.
We have a pretty big angular project with around 1500 scss files.
We've just manually replaced sass with sass-embedded in our webpack configuration and got 27% first compilation time reduction – on average from 140s to 100s, so it makes sense to revisit it and probably make a standard ng-cli sass implementation.