Skip to content

Commit

Permalink
feat: added the modern-compiler value for API to reuse compiler pro…
Browse files Browse the repository at this point in the history
…cess (#1195)
  • Loading branch information
renspoesse authored Apr 9, 2024
1 parent 13f0dc8 commit cef40a8
Show file tree
Hide file tree
Showing 21 changed files with 36,650 additions and 2,034 deletions.
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);
} 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 @@ async function getSassOptions(
};
}

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 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
}

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 @@ function getCompileFn(implementation, options) {
};
}

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();
});
}
}
return sassModernCompilers
.get(implementation)
.compileStringAsync(data, rest);
}

return implementation.compileStringAsync(data, rest);
};
}

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

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`] = `[]`;
Loading

0 comments on commit cef40a8

Please sign in to comment.