sass-loader
sass-loader copied to clipboard
Dart Sass without fibers should use renderSync instead of render
- Operating System: Windows
- Node Version: 10.16.0
- NPM Version: 6.9.0
- webpack Version: 4.30.0
- sass-loader Version: 7.1.0
Expected Behavior
When using Dart Sass and not using fibers, the renderSync method should always be used instead of the render method (see https://github.com/sass/dart-sass#javascript-api, https://github.com/webpack-contrib/sass-loader/issues/435#issuecomment-349450103 and https://github.com/sass/dart-sass/issues/744#issuecomment-507429974 for details). Always using render has severe performance implications.
Actual Behavior
The render method is always used with Dart sass.
Code
https://github.com/webpack-contrib/sass-loader/blob/e279f2a129eee0bd0b624b5acd498f23a81ee35e/lib/loader.js#L137-L144
How Do We Reproduce?
No external reproduction needed. It's in the source code for this package.
Thanks for issue, i will investigate this for next major release, i think i will start work on next release at this week, a lot of other issues
SGTM, thanks for looking at it!
We could make it configurable via loader options. This pushes the responsibility/complexity back to the user. The problem is that the sass-loader has no clue if your project uses any custom importer where the async API is necessary.
I should also mention that compiling something synchronously is one of the worst things you can do in a webpack build. In a regular webpack build there are hundreds of async module builds simultaneously. If you do something synchronously, it will pause all other module builds. I'm pretty sure that most people will get worse performance results if they do something synchronously 😁
I think configurable makes sense if the plugin cannot determine it. I can compare performance numbers if you guide me a little bit on how I can change it in my node modules. I tried to change it myself in https://github.com/sass/dart-sass/issues/744#issuecomment-507245355 but it looks like I was missing something.
We could make it configurable via loader options. This pushes the responsibility/complexity back to the user. The problem is that the sass-loader has no clue if your project uses any custom importer where the async API is necessary.
This would make sense, but the default should still probably be running synchronously (which means WebPack's custom importer should be synchronous as well).
I should also mention that compiling something synchronously is one of the worst things you can do in a webpack build. In a regular webpack build there are hundreds of async module builds simultaneously. If you do something synchronously, it will pause all other module builds. I'm pretty sure that most people will get worse performance results if they do something synchronously :grin:
The logic of compiling Sass—which is by far the bottleneck of Sass compilation—is inherently synchronous. There's nothing about parsing strings or manipulating ASTs that can be done out-of-process, so making it asynchronous doesn't buy you anything in terms of speed (and in fact makes it much slower because it has to bounce back to the event loop all the time). The only reason it has an asynchronous mode at all is to support asynchronous plugins.
This would make sense, but the default should still probably be running synchronously (which means WebPack's custom importer should be synchronous as well).
In theory it is possible https://github.com/webpack/enhanced-resolve#resolve (we need use sync), but here we will have other problem - it is decrease sass compilation time, but increase webpack compilation time, no golden way here
The overhead of running Sass asynchronously tends to range between 2x and 3x the total synchronous compilation time for large projects, not to mention the memory overhead that @filipesilva is running into. This dwarfs file IO time, which means it's also likely to dwarf the benefits you'd get from increased parallelism while waiting on file IO.
Hi @nex3 !
Thank you for your work!
1 - Are you considering caching? To increase the performance of file processing
2 - sass.renderSync - Is it recommended? I mean Dart-Sass for JS npm install sass --save-dev.
1 - Are you considering caching? To increase the performance of file processing
Filesystem operations aren't the bottleneck here. The issue, as I explained above, is the overhead of going back to the event loop for every method call in asynchronous mode.
2 -
sass.renderSync- Is it recommended? I mean Dart-Sass for JSnpm install sass --save-dev.
Yes, renderSync() is recommended for Dart Sass.
@nex3 Thank you!
Can I set your avatar in my plugin?
I'd prefer it if you didn't.
I'd prefer it if you didn't.
@nex3 Ok. I will not add a photo of your avatar. It was just needed for the quote you made. Then I'll just add your nickname.
Here are these quotes
The logic of compiling Sass—which is by far the bottleneck of Sass compilation—is inherently synchronous. There's nothing about parsing strings or manipulating ASTs that can be done out-of-process, so making it asynchronous doesn't buy you anything in terms of speed (and in fact makes it much slower because it has to bounce back to the event loop all the time). The only reason it has an asynchronous mode at all is to support asynchronous plugins.
The overhead of running Sass asynchronously tends to range between 2x and 3x the total synchronous compilation time for large projects, not to mention the memory overhead that @filipesilva is running into. This dwarfs file IO time, which means it's also likely to dwarf the benefits you'd get from increased parallelism while waiting on file IO.
What’s the status of this issue? I thinks what @jhnns proposed—pushing the responsibility/complexity back to the user—is the best way forward. Make sass-loader async by default, but strongly recommend (in documentation) switching to sync API when using Dart Sass.
We can't use sync api because we need resolve your @import/@use and etc, it will bring a big losing of perf
We can't use sync api because we need resolve your
@import/@useand etc, it will bring a big losing of perf
This is still developer/user issue and it’s something that could be mentioned in documentation. Currently there really isn’t any good way forward other than opt-in to sync API and deal with consequences.
As for resolving module at-rules, that’s included inside stats.includedFiles which is provided by Sass render result and it’s not related to any Webpack implementation other than custom Webpack importer.
We can't enable sync api, resolver are always async
We can't enable sync api, resolver are always async
Do you mean Webpack resolver or Sass resolver? Because Webpack enhanced resolve has sync option IIRC.
1 - Are you considering caching? To increase the performance of file processing
Are we not caching the results?