-
-
Notifications
You must be signed in to change notification settings - Fork 431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
perf: reuse compiler process when using sass-embedded #1195
perf: reuse compiler process when using sass-embedded #1195
Conversation
This implements the Shared Resources proposal that was accepted and implemented in Dart Sass 1.70.0. By reusing the same compiler process when compiling multiple files, this significantly improves performance for tools like webpack. Closes: webpack-contrib#1163
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you sign the CLA?
@@ -74,7 +74,7 @@ async function loader(content) { | |||
let result; | |||
|
|||
try { | |||
result = await compile(sassOptions, options); | |||
result = await compile(sassOptions); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed unused argument.
src/utils.js
Outdated
if (!sassEmbeddedCompiler) { | ||
// Create a long-running compiler process that can be reused | ||
// for compiling individual files. | ||
sassEmbeddedCompiler = await implementation.initAsyncCompiler(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the lifetime of a webpack loader. If webpack provides some hook for this, we could close the compiler process by calling sassEmbeddedCompiler.dispose()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Firstly let's implement the modern-compiler
for the api
option, because it is different mode and can have differents problems, in future when sass finished and stabilizated everythings we will use modern-compiler
API by default.
Yes, we should close dispose
compiler, we can use such code:
if (!sassEmbeddedCompiler && loader._compiler) {
sassEmbeddedCompiler = await implementation.initAsyncCompiler();
loader._compiler.hooks.shutdown.tap("name", () => { sassEmbeddedCompiler.dispose() })
}
Some people can run loader in multi threading way and there is no compiler
in the such case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also will be great to make some benches, for example for bootstrap to undestand how it is better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some people can run loader in multi threading way and there is no
compiler
in the such case
Could you clarify this? (Why) can we not use the long-running subprocess in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is slow for perf, initial start will be very long and we don't need subprocess
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've implemented your suggestions. Re:
Also will be great to make some benches, for example for bootstrap to undestand how it is better
is there a pre-existing repo or setup I can use to benchmark this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, let's just check it, I will put it in release notes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For what it's worth, I don't have the exact numbers but on a larger project I'm working on, modern-compiler
is up to 10 seconds faster than modern
. Also modern
would just crash when compiling a changed file that's imported in various other files, whereas with modern-compiler
it works fine.
src/utils.js
Outdated
// there is no webpack compiler object in such case. | ||
if (webpackCompiler) { | ||
const key = isDartSass ? "dart-sass" : "sass-embedded"; | ||
if (!sassModernCompilers[key]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if getCompileFn()
can be invoked with different (implementation) options for a single instance of the sass-loader module, but I guess it can? In that case we should maintain a compiler instance for each implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, let's use WeakMap
with options to prevent such behaviour and memory leaking
src/utils.js
Outdated
// for compiling individual files. | ||
const compiler = await implementation.initAsyncCompiler(); | ||
webpackCompiler.hooks.shutdown.tap("sass-loader", () => { | ||
compiler.dispose(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my debugging this hook was never called; not sure when it should be. In any case, should we delete sassModernCompilers[key]
after disposing? If webpack may reuse the sass-loader
module after the shutdown
phase, we should, otherwise the compiler won't be recreated on the next run.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After shutdown
should nothing happend in theory, weird, it should happend
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, let's look at tests and solve small nitpicks above
src/utils.js
Outdated
}); | ||
} | ||
} | ||
return sassModernCompilers.get(implementation).compileStringAsync(data, rest); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a test case where we have two sass loaders with different options and use modern-compiler
, just make sure everything works fine
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the test from 183765a look good to you? I'm not sure how to otherwise have two sass-loaders; we can't chain them within a single webpack config, right? Because they don't output Sass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with test, maybe I will add more later, want to look at this today
Thank you for your work, looks like a test passed, so let's add for two loader with different options and we can merge it, I will check the shutdown hook |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1195 +/- ##
==========================================
- Coverage 94.44% 94.11% -0.33%
==========================================
Files 3 3
Lines 360 374 +14
Branches 132 137 +5
==========================================
+ Hits 340 352 +12
- Misses 18 20 +2
Partials 2 2 ☔ View full report in Codecov by Sentry. |
2d39fc1
to
ea88129
Compare
Thank you, I will make perf benchmarks and show them in the release, also I want to finish built-in webpack resolver support for modern and modern-compiler API |
It really faster (
Just
Around 10x times |
This PR contains a:
Motivation / Use-Case
This implements the Shared Resources proposal that was accepted and implemented in Dart Sass 1.70.0. By reusing the same compiler process when compiling multiple files, this significantly improves performance for tools like webpack.
Breaking Changes
None
Additional Info
Closes: #1163