Skip to content
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

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -657,12 +657,12 @@ module.exports = {
Type:

```ts
type api = "legacy" | "modern";
type api = "legacy" | "modern" | "modern-compiler";
```

Default: `"legacy"`

Allows you to switch between `legacy` and `modern` API. You can find more information [here](https://sass-lang.com/documentation/js-api).
Allows you to switch between `legacy` and `modern` API. You can find more information [here](https://sass-lang.com/documentation/js-api). The `modern-compiler` option enables the modern API with support for [Shared Resources](https://github.com/sass/sass/blob/main/accepted/shared-resources.d.ts.md).

> **Warning**
>
Expand Down
7 changes: 4 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ async function loader(content) {
: true;

if (shouldUseWebpackImporter) {
const isModernAPI = options.api === "modern";
const isModernAPI =
options.api === "modern" || options.api === "modern-compiler";

if (!isModernAPI) {
const { includePaths } = sassOptions;
Expand All @@ -65,7 +66,7 @@ async function loader(content) {
let compile;

try {
compile = getCompileFn(implementation, options);
compile = getCompileFn(this, implementation, options);
} catch (error) {
callback(error);
return;
Expand All @@ -74,7 +75,7 @@ async function loader(content) {
let result;

try {
result = await compile(sassOptions, options);
result = await compile(sassOptions);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed unused argument.

} catch (error) {
// There are situations when the `file`/`span.url` property do not exist
// Modern API
Expand Down
2 changes: 1 addition & 1 deletion src/options.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"api": {
"description": "Switch between old and modern API for `sass` (`Dart Sass`) and `Sass Embedded` implementations.",
"link": "https://github.com/webpack-contrib/sass-loader#sassoptions",
"enum": ["legacy", "modern"]
"enum": ["legacy", "modern", "modern-compiler"]
},
"sassOptions": {
"description": "Options for `node-sass` or `sass` (`Dart Sass`) implementation.",
Expand Down
40 changes: 37 additions & 3 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@
};
}

const isModernAPI = loaderOptions.api === "modern";
const isModernAPI =
loaderOptions.api === "modern" || loaderOptions.api === "modern-compiler";
const { resourcePath } = loaderContext;

if (isModernAPI) {
Expand Down Expand Up @@ -650,15 +651,17 @@
}

let nodeSassJobQueue = null;
const sassModernCompilers = new WeakMap();

/**
* Verifies that the implementation and version of Sass is supported by this loader.
*
* @param {Object} loaderContext
* @param {Object} implementation
* @param {Object} options
* @returns {Function}
*/
function getCompileFn(implementation, options) {
function getCompileFn(loaderContext, implementation, options) {
const isNewSass =
implementation.info.includes("dart-sass") ||
implementation.info.includes("sass-embedded");
Expand All @@ -672,6 +675,37 @@
};
}

if (options.api === "modern-compiler") {
return async (sassOptions) => {
// eslint-disable-next-line no-underscore-dangle
const webpackCompiler = loaderContext._compiler;
const { data, ...rest } = sassOptions;

// Some people can run the loader in a multi-threading way;
// there is no webpack compiler object in such case.
if (webpackCompiler) {
if (!sassModernCompilers.has(implementation)) {
// Create a long-running compiler process that can be reused
// for compiling individual files.
const compiler = await implementation.initAsyncCompiler();
// Check again because awaiting the initialization function
// introduces a race condition.
if (!sassModernCompilers.has(implementation)) {
sassModernCompilers.set(implementation, compiler);
webpackCompiler.hooks.shutdown.tap("sass-loader", () => {
compiler.dispose();

Check warning on line 696 in src/utils.js

View check run for this annotation

Codecov / codecov/patch

src/utils.js#L696

Added line #L696 was not covered by tests
});
}
}
return sassModernCompilers
.get(implementation)
.compileStringAsync(data, rest);
}

return implementation.compileStringAsync(data, rest);

Check warning on line 705 in src/utils.js

View check run for this annotation

Codecov / codecov/patch

src/utils.js#L705

Added line #L705 was not covered by tests
};
}

return (sassOptions) =>
new Promise((resolve, reject) => {
implementation.render(sassOptions, (error, result) => {
Expand All @@ -686,7 +720,7 @@
});
}

if (options.api === "modern") {
if (options.api === "modern" || options.api === "modern-compiler") {
throw new Error("Modern API is not supported for 'node-sass'");
}

Expand Down
176 changes: 176 additions & 0 deletions test/__snapshots__/additionalData-option.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,34 @@ exports[`additionalData option should use same EOL on all os ('dart-sass', 'mode

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"a {
color: hotpink;
}

body {
color: hotpink;
}"
`;

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"a {
color: red;
}

body {
color: hotpink;
}"
`;

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('dart-sass', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('node-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"a {
color: hotpink; }
Expand Down Expand Up @@ -138,6 +166,34 @@ exports[`additionalData option should use same EOL on all os ('sass-embedded', '

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"a {
color: hotpink;
}

body {
color: hotpink;
}"
`;

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"a {
color: red;
}

body {
color: hotpink;
}"
`;

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should use same EOL on all os ('sass-embedded', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a function ('dart-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
Expand Down Expand Up @@ -178,6 +234,26 @@ exports[`additionalData option should work as a function ('dart-sass', 'modern'

exports[`additionalData option should work as a function ('dart-sass', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a function ('dart-sass', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a function ('dart-sass', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a function ('dart-sass', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a function ('dart-sass', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a function ('dart-sass', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a function ('dart-sass', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a function ('node-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink; }
Expand Down Expand Up @@ -238,6 +314,26 @@ exports[`additionalData option should work as a function ('sass-embedded', 'mode

exports[`additionalData option should work as a function ('sass-embedded', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a function ('sass-embedded', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a function ('sass-embedded', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a function ('sass-embedded', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a function ('sass-embedded', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a function ('sass-embedded', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a function ('sass-embedded', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a string ('dart-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
Expand Down Expand Up @@ -278,6 +374,26 @@ exports[`additionalData option should work as a string ('dart-sass', 'modern' AP

exports[`additionalData option should work as a string ('dart-sass', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a string ('dart-sass', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a string ('dart-sass', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a string ('dart-sass', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a string ('dart-sass', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a string ('dart-sass', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a string ('dart-sass', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a string ('node-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink; }
Expand Down Expand Up @@ -338,6 +454,26 @@ exports[`additionalData option should work as a string ('sass-embedded', 'modern

exports[`additionalData option should work as a string ('sass-embedded', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a string ('sass-embedded', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a string ('sass-embedded', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a string ('sass-embedded', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as a string ('sass-embedded', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as a string ('sass-embedded', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as a string ('sass-embedded', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as an async function ('dart-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
Expand Down Expand Up @@ -378,6 +514,26 @@ exports[`additionalData option should work as an async function ('dart-sass', 'm

exports[`additionalData option should work as an async function ('dart-sass', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as an async function ('dart-sass', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as an async function ('dart-sass', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as an async function ('dart-sass', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as an async function ('dart-sass', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as an async function ('dart-sass', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as an async function ('dart-sass', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as an async function ('node-sass', 'legacy' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink; }
Expand Down Expand Up @@ -437,3 +593,23 @@ exports[`additionalData option should work as an async function ('sass-embedded'
exports[`additionalData option should work as an async function ('sass-embedded', 'modern' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern' API, 'scss' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern-compiler' API, 'sass' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern-compiler' API, 'sass' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern-compiler' API, 'sass' syntax): warnings 1`] = `[]`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern-compiler' API, 'scss' syntax): css 1`] = `
"body {
color: hotpink;
}"
`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern-compiler' API, 'scss' syntax): errors 1`] = `[]`;

exports[`additionalData option should work as an async function ('sass-embedded', 'modern-compiler' API, 'scss' syntax): warnings 1`] = `[]`;