sass-loader 14.1.1 → 14.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/index.js +6 -4
- package/dist/options.json +1 -1
- package/dist/utils.js +91 -11
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -657,16 +657,16 @@ module.exports = {
|
|
|
657
657
|
Type:
|
|
658
658
|
|
|
659
659
|
```ts
|
|
660
|
-
type api = "legacy" | "modern";
|
|
660
|
+
type api = "legacy" | "modern" | "modern-compiler";
|
|
661
661
|
```
|
|
662
662
|
|
|
663
663
|
Default: `"legacy"`
|
|
664
664
|
|
|
665
|
-
Allows you to switch between `legacy` and `modern` API. You can find more information [here](https://sass-lang.com/documentation/js-api).
|
|
665
|
+
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).
|
|
666
666
|
|
|
667
|
-
> **
|
|
667
|
+
> **Note**
|
|
668
668
|
>
|
|
669
|
-
>
|
|
669
|
+
> Using `modern-compiler` and `sass-embedded` together significantly improve performance and decrease built time. We strongly recommend their use. We will enable them by default in a future major release.
|
|
670
670
|
|
|
671
671
|
> **Warning**
|
|
672
672
|
>
|
package/dist/index.js
CHANGED
|
@@ -29,26 +29,28 @@ async function loader(content) {
|
|
|
29
29
|
const sassOptions = await (0, _utils.getSassOptions)(this, options, content, implementation, useSourceMap);
|
|
30
30
|
const shouldUseWebpackImporter = typeof options.webpackImporter === "boolean" ? options.webpackImporter : true;
|
|
31
31
|
if (shouldUseWebpackImporter) {
|
|
32
|
-
const isModernAPI = options.api === "modern";
|
|
32
|
+
const isModernAPI = options.api === "modern" || options.api === "modern-compiler";
|
|
33
33
|
if (!isModernAPI) {
|
|
34
34
|
const {
|
|
35
35
|
includePaths
|
|
36
36
|
} = sassOptions;
|
|
37
37
|
sassOptions.importer.push((0, _utils.getWebpackImporter)(this, implementation, includePaths));
|
|
38
38
|
} else {
|
|
39
|
-
sassOptions.importers.push(
|
|
39
|
+
sassOptions.importers.push(
|
|
40
|
+
// No need to pass `loadPaths`, because modern API handle them itself
|
|
41
|
+
(0, _utils.getModernWebpackImporter)(this, implementation, []));
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
44
|
let compile;
|
|
43
45
|
try {
|
|
44
|
-
compile = (0, _utils.getCompileFn)(implementation, options);
|
|
46
|
+
compile = (0, _utils.getCompileFn)(this, implementation, options);
|
|
45
47
|
} catch (error) {
|
|
46
48
|
callback(error);
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
51
|
let result;
|
|
50
52
|
try {
|
|
51
|
-
result = await compile(sassOptions
|
|
53
|
+
result = await compile(sassOptions);
|
|
52
54
|
} catch (error) {
|
|
53
55
|
// There are situations when the `file`/`span.url` property do not exist
|
|
54
56
|
// Modern API
|
package/dist/options.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"api": {
|
|
18
18
|
"description": "Switch between old and modern API for `sass` (`Dart Sass`) and `Sass Embedded` implementations.",
|
|
19
19
|
"link": "https://github.com/webpack-contrib/sass-loader#sassoptions",
|
|
20
|
-
"enum": ["legacy", "modern"]
|
|
20
|
+
"enum": ["legacy", "modern", "modern-compiler"]
|
|
21
21
|
},
|
|
22
22
|
"sassOptions": {
|
|
23
23
|
"description": "Options for `node-sass` or `sass` (`Dart Sass`) implementation.",
|
package/dist/utils.js
CHANGED
|
@@ -145,7 +145,7 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
|
|
|
145
145
|
}
|
|
146
146
|
};
|
|
147
147
|
}
|
|
148
|
-
const isModernAPI = loaderOptions.api === "modern";
|
|
148
|
+
const isModernAPI = loaderOptions.api === "modern" || loaderOptions.api === "modern-compiler";
|
|
149
149
|
const {
|
|
150
150
|
resourcePath
|
|
151
151
|
} = loaderContext;
|
|
@@ -171,6 +171,9 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
|
|
|
171
171
|
sassOptions.syntax = "css";
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
|
+
sassOptions.loadPaths = [].concat(
|
|
175
|
+
// We use `loadPaths` in context for resolver, so it should be always absolute
|
|
176
|
+
(sassOptions.loadPaths ? sassOptions.loadPaths.slice() : []).map(includePath => _path.default.isAbsolute(includePath) ? includePath : _path.default.join(process.cwd(), includePath))).concat(process.env.SASS_PATH ? process.env.SASS_PATH.split(process.platform === "win32" ? ";" : ":") : []);
|
|
174
177
|
sassOptions.importers = sassOptions.importers ? Array.isArray(sassOptions.importers) ? sassOptions.importers.slice() : [sassOptions.importers] : [];
|
|
175
178
|
} else {
|
|
176
179
|
sassOptions.file = resourcePath;
|
|
@@ -346,7 +349,7 @@ const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
|
|
|
346
349
|
* @throws If a compatible Sass implementation cannot be found.
|
|
347
350
|
*/
|
|
348
351
|
function getWebpackResolver(resolverFactory, implementation, includePaths = []) {
|
|
349
|
-
const
|
|
352
|
+
const isModernSass = implementation && (implementation.info.includes("dart-sass") || implementation.info.includes("sass-embedded"));
|
|
350
353
|
// We only have one difference with the built-in sass resolution logic and out resolution logic:
|
|
351
354
|
// First, we look at the files starting with `_`, then without `_` (i.e. `_name.sass`, `_name.scss`, `_name.css`, `name.sass`, `name.scss`, `name.css`),
|
|
352
355
|
// although `sass` look together by extensions (i.e. `_name.sass`/`name.sass`/`_name.scss`/`name.scss`/`_name.css`/`name.css`).
|
|
@@ -403,7 +406,7 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
|
|
|
403
406
|
// See https://github.com/webpack/webpack/issues/12340
|
|
404
407
|
// Because `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`
|
|
405
408
|
// custom importer may not return `{ file: '/path/to/name.ext' }` and therefore our `context` will be relative
|
|
406
|
-
if (!
|
|
409
|
+
if (!isModernSass && !_path.default.isAbsolute(context)) {
|
|
407
410
|
return Promise.reject();
|
|
408
411
|
}
|
|
409
412
|
const originalRequest = request;
|
|
@@ -441,7 +444,7 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
|
|
|
441
444
|
const sassPossibleRequests = getPossibleRequests(request, false, fromImport);
|
|
442
445
|
|
|
443
446
|
// `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`, so we need emulate this too
|
|
444
|
-
if (!
|
|
447
|
+
if (!isModernSass) {
|
|
445
448
|
resolutionMap = resolutionMap.concat({
|
|
446
449
|
resolve: fromImport ? sassImportResolve : sassModuleResolve,
|
|
447
450
|
context: _path.default.dirname(context),
|
|
@@ -468,13 +471,57 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
|
|
|
468
471
|
};
|
|
469
472
|
}
|
|
470
473
|
const MATCH_CSS = /\.css$/i;
|
|
471
|
-
function getModernWebpackImporter() {
|
|
474
|
+
function getModernWebpackImporter(loaderContext, implementation, loadPaths) {
|
|
475
|
+
const resolve = getWebpackResolver(loaderContext.getResolve, implementation, loadPaths);
|
|
472
476
|
return {
|
|
473
|
-
async canonicalize() {
|
|
474
|
-
|
|
477
|
+
async canonicalize(originalUrl, context) {
|
|
478
|
+
const {
|
|
479
|
+
fromImport
|
|
480
|
+
} = context;
|
|
481
|
+
const prev = context.containingUrl ? _url.default.fileURLToPath(context.containingUrl.toString()) : loaderContext.resourcePath;
|
|
482
|
+
let result;
|
|
483
|
+
try {
|
|
484
|
+
result = await resolve(prev, originalUrl, fromImport);
|
|
485
|
+
} catch (err) {
|
|
486
|
+
// If no stylesheets are found, the importer should return null.
|
|
487
|
+
return null;
|
|
488
|
+
}
|
|
489
|
+
loaderContext.addDependency(_path.default.normalize(result));
|
|
490
|
+
return _url.default.pathToFileURL(result);
|
|
475
491
|
},
|
|
476
|
-
load() {
|
|
477
|
-
|
|
492
|
+
async load(canonicalUrl) {
|
|
493
|
+
const ext = _path.default.extname(canonicalUrl.pathname);
|
|
494
|
+
let syntax;
|
|
495
|
+
if (ext && ext.toLowerCase() === ".scss") {
|
|
496
|
+
syntax = "scss";
|
|
497
|
+
} else if (ext && ext.toLowerCase() === ".sass") {
|
|
498
|
+
syntax = "indented";
|
|
499
|
+
} else if (ext && ext.toLowerCase() === ".css") {
|
|
500
|
+
syntax = "css";
|
|
501
|
+
} else {
|
|
502
|
+
// Fallback to default value
|
|
503
|
+
syntax = "scss";
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
const contents = await new Promise((resolve, reject) => {
|
|
507
|
+
// Old version of `enhanced-resolve` supports only path as a string
|
|
508
|
+
// TODO simplify in the next major release and pass URL
|
|
509
|
+
const canonicalPath = _url.default.fileURLToPath(canonicalUrl);
|
|
510
|
+
loaderContext.fs.readFile(canonicalPath, "utf8", (err, content) => {
|
|
511
|
+
if (err) {
|
|
512
|
+
reject(err);
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
resolve(content);
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
return {
|
|
519
|
+
contents,
|
|
520
|
+
syntax
|
|
521
|
+
};
|
|
522
|
+
} catch (err) {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
478
525
|
}
|
|
479
526
|
};
|
|
480
527
|
}
|
|
@@ -504,15 +551,17 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
|
|
|
504
551
|
};
|
|
505
552
|
}
|
|
506
553
|
let nodeSassJobQueue = null;
|
|
554
|
+
const sassModernCompilers = new WeakMap();
|
|
507
555
|
|
|
508
556
|
/**
|
|
509
557
|
* Verifies that the implementation and version of Sass is supported by this loader.
|
|
510
558
|
*
|
|
559
|
+
* @param {Object} loaderContext
|
|
511
560
|
* @param {Object} implementation
|
|
512
561
|
* @param {Object} options
|
|
513
562
|
* @returns {Function}
|
|
514
563
|
*/
|
|
515
|
-
function getCompileFn(implementation, options) {
|
|
564
|
+
function getCompileFn(loaderContext, implementation, options) {
|
|
516
565
|
const isNewSass = implementation.info.includes("dart-sass") || implementation.info.includes("sass-embedded");
|
|
517
566
|
if (isNewSass) {
|
|
518
567
|
if (options.api === "modern") {
|
|
@@ -524,6 +573,37 @@ function getCompileFn(implementation, options) {
|
|
|
524
573
|
return implementation.compileStringAsync(data, rest);
|
|
525
574
|
};
|
|
526
575
|
}
|
|
576
|
+
if (options.api === "modern-compiler") {
|
|
577
|
+
return async sassOptions => {
|
|
578
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
579
|
+
const webpackCompiler = loaderContext._compiler;
|
|
580
|
+
const {
|
|
581
|
+
data,
|
|
582
|
+
...rest
|
|
583
|
+
} = sassOptions;
|
|
584
|
+
|
|
585
|
+
// Some people can run the loader in a multi-threading way;
|
|
586
|
+
// there is no webpack compiler object in such case.
|
|
587
|
+
if (webpackCompiler) {
|
|
588
|
+
if (!sassModernCompilers.has(implementation)) {
|
|
589
|
+
// Create a long-running compiler process that can be reused
|
|
590
|
+
// for compiling individual files.
|
|
591
|
+
const compiler = await implementation.initAsyncCompiler();
|
|
592
|
+
|
|
593
|
+
// Check again because awaiting the initialization function
|
|
594
|
+
// introduces a race condition.
|
|
595
|
+
if (!sassModernCompilers.has(webpackCompiler)) {
|
|
596
|
+
sassModernCompilers.set(webpackCompiler, compiler);
|
|
597
|
+
webpackCompiler.hooks.shutdown.tap("sass-loader", () => {
|
|
598
|
+
compiler.dispose();
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return sassModernCompilers.get(webpackCompiler).compileStringAsync(data, rest);
|
|
603
|
+
}
|
|
604
|
+
return implementation.compileStringAsync(data, rest);
|
|
605
|
+
};
|
|
606
|
+
}
|
|
527
607
|
return sassOptions => new Promise((resolve, reject) => {
|
|
528
608
|
implementation.render(sassOptions, (error, result) => {
|
|
529
609
|
if (error) {
|
|
@@ -534,7 +614,7 @@ function getCompileFn(implementation, options) {
|
|
|
534
614
|
});
|
|
535
615
|
});
|
|
536
616
|
}
|
|
537
|
-
if (options.api === "modern") {
|
|
617
|
+
if (options.api === "modern" || options.api === "modern-compiler") {
|
|
538
618
|
throw new Error("Modern API is not supported for 'node-sass'");
|
|
539
619
|
}
|
|
540
620
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sass-loader",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.2.0",
|
|
4
4
|
"description": "Sass loader for webpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "webpack-contrib/sass-loader",
|
|
@@ -70,8 +70,8 @@
|
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@babel/cli": "^7.23.4",
|
|
73
|
-
"@babel/core": "^7.
|
|
74
|
-
"@babel/preset-env": "^7.
|
|
73
|
+
"@babel/core": "^7.24.0",
|
|
74
|
+
"@babel/preset-env": "^7.24.0",
|
|
75
75
|
"@commitlint/cli": "^18.4.4",
|
|
76
76
|
"@commitlint/config-conventional": "^18.4.4",
|
|
77
77
|
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
|
|
@@ -80,12 +80,12 @@
|
|
|
80
80
|
"bootstrap-v4": "npm:bootstrap@^4.5.3",
|
|
81
81
|
"bootstrap-v5": "npm:bootstrap@^5.0.1",
|
|
82
82
|
"cross-env": "^7.0.3",
|
|
83
|
-
"cspell": "^8.
|
|
83
|
+
"cspell": "^8.6.0",
|
|
84
84
|
"css-loader": "^6.9.0",
|
|
85
85
|
"del": "^6.1.1",
|
|
86
86
|
"del-cli": "^5.1.0",
|
|
87
|
-
"enhanced-resolve": "^5.15.
|
|
88
|
-
"eslint": "^8.
|
|
87
|
+
"enhanced-resolve": "^5.15.1",
|
|
88
|
+
"eslint": "^8.57.0",
|
|
89
89
|
"eslint-config-prettier": "^9.1.0",
|
|
90
90
|
"eslint-plugin-import": "^2.28.0",
|
|
91
91
|
"file-loader": "^6.2.0",
|
|
@@ -95,17 +95,19 @@
|
|
|
95
95
|
"jest-environment-node-single-context": "^29.1.0",
|
|
96
96
|
"lint-staged": "^15.2.0",
|
|
97
97
|
"material-components-web": "^9.0.0",
|
|
98
|
-
"memfs": "^4.
|
|
98
|
+
"memfs": "^4.7.7",
|
|
99
99
|
"node-sass": "^9.0.0",
|
|
100
100
|
"node-sass-glob-importer": "^5.3.2",
|
|
101
101
|
"npm-run-all": "^4.1.5",
|
|
102
102
|
"prettier": "^3.2.2",
|
|
103
|
-
"sass": "^1.
|
|
104
|
-
"sass-embedded": "^1.
|
|
103
|
+
"sass": "^1.71.1",
|
|
104
|
+
"sass-embedded": "^1.71.1",
|
|
105
105
|
"semver": "^7.5.4",
|
|
106
106
|
"standard-version": "^9.3.1",
|
|
107
107
|
"style-loader": "^3.3.4",
|
|
108
|
-
"webpack": "^5.88.2"
|
|
108
|
+
"webpack": "^5.88.2",
|
|
109
|
+
"webpack-cli": "^5.1.4",
|
|
110
|
+
"webpack-dev-server": "^5.0.4"
|
|
109
111
|
},
|
|
110
112
|
"keywords": [
|
|
111
113
|
"sass",
|