sass-loader 12.4.0 → 13.0.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 +116 -23
- package/dist/SassError.js +11 -9
- package/dist/index.js +50 -21
- package/dist/options.json +5 -0
- package/dist/utils.js +204 -116
- package/package.json +25 -19
package/README.md
CHANGED
|
@@ -27,7 +27,19 @@ To begin, you'll need to install `sass-loader`:
|
|
|
27
27
|
npm install sass-loader sass webpack --save-dev
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
or
|
|
31
|
+
|
|
32
|
+
```console
|
|
33
|
+
yarn add -D sass-loader sass webpack
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
or
|
|
37
|
+
|
|
38
|
+
```console
|
|
39
|
+
pnpm add -D sass-loader sass webpack
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`sass-loader` requires you to install either [Dart Sass](https://github.com/sass/dart-sass), [Node Sass](https://github.com/sass/node-sass) on your own (more documentation can be found below) or [Sass Embedded](https://github.com/sass/embedded-host-node).
|
|
31
43
|
|
|
32
44
|
This allows you to control the versions of all your dependencies, and to choose which Sass implementation to use.
|
|
33
45
|
|
|
@@ -35,6 +47,8 @@ This allows you to control the versions of all your dependencies, and to choose
|
|
|
35
47
|
|
|
36
48
|
> ⚠ [Node Sass](https://github.com/sass/node-sass) does not work with [Yarn PnP](https://classic.yarnpkg.com/en/docs/pnp/) feature and doesn't support [@use rule](https://sass-lang.com/documentation/at-rules/use).
|
|
37
49
|
|
|
50
|
+
> ⚠ [Sass Embedded](https://github.com/sass/embedded-host-node) is experimental and in `beta`, therefore some features may not work
|
|
51
|
+
|
|
38
52
|
Chain the `sass-loader` with the [css-loader](https://github.com/webpack-contrib/css-loader) and the [style-loader](https://github.com/webpack-contrib/style-loader) to immediately apply all styles to the DOM or the [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin) to extract it into a separate file.
|
|
39
53
|
|
|
40
54
|
Then add the loader to your Webpack configuration. For example:
|
|
@@ -119,18 +133,21 @@ Thankfully there are a two solutions to this problem:
|
|
|
119
133
|
|
|
120
134
|
## Options
|
|
121
135
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
| **[`webpackImporter`](#webpackimporter)** | `{Boolean}` | `true` | Enables/Disables the default Webpack importer. |
|
|
129
|
-
| **[`warnRuleAsWarning`](#warnruleaswarning)** | `{Boolean}` | `false` | Treats the `@warn` rule as a webpack warning. |
|
|
136
|
+
- **[`implementation`](#implementation)**
|
|
137
|
+
- **[`sassOptions`](#sassoptions)**
|
|
138
|
+
- **[`sourceMap`](#sourcemap)**
|
|
139
|
+
- **[`additionalData`](#additionaldata)**
|
|
140
|
+
- **[`webpackImporter`](#webpackimporter)**
|
|
141
|
+
- **[`warnRuleAsWarning`](#warnruleaswarning)**
|
|
130
142
|
|
|
131
143
|
### `implementation`
|
|
132
144
|
|
|
133
|
-
Type:
|
|
145
|
+
Type:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
type implementation = object | string;
|
|
149
|
+
```
|
|
150
|
+
|
|
134
151
|
Default: `sass`
|
|
135
152
|
|
|
136
153
|
The special `implementation` option determines which implementation of Sass to use.
|
|
@@ -169,7 +186,7 @@ In order to avoid this situation you can use the `implementation` option.
|
|
|
169
186
|
|
|
170
187
|
The `implementation` options either accepts `sass` (`Dart Sass`) or `node-sass` as a module.
|
|
171
188
|
|
|
172
|
-
####
|
|
189
|
+
#### `object`
|
|
173
190
|
|
|
174
191
|
For example, to use Dart Sass, you'd pass:
|
|
175
192
|
|
|
@@ -196,7 +213,7 @@ module.exports = {
|
|
|
196
213
|
};
|
|
197
214
|
```
|
|
198
215
|
|
|
199
|
-
####
|
|
216
|
+
#### `string`
|
|
200
217
|
|
|
201
218
|
For example, to use Dart Sass, you'd pass:
|
|
202
219
|
|
|
@@ -302,7 +319,18 @@ module.exports = {
|
|
|
302
319
|
|
|
303
320
|
### `sassOptions`
|
|
304
321
|
|
|
305
|
-
Type:
|
|
322
|
+
Type:
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
type sassOptions =
|
|
326
|
+
| import("sass").LegacyOptions<"async">
|
|
327
|
+
| ((
|
|
328
|
+
content: string | Buffer,
|
|
329
|
+
loaderContext: LoaderContext,
|
|
330
|
+
meta: any
|
|
331
|
+
) => import("sass").LegacyOptions<"async">);
|
|
332
|
+
```
|
|
333
|
+
|
|
306
334
|
Default: defaults values for Sass implementation
|
|
307
335
|
|
|
308
336
|
Options for [Dart Sass](http://sass-lang.com/dart-sass) or [Node Sass](https://github.com/sass/node-sass) implementation.
|
|
@@ -321,12 +349,12 @@ There is a slight difference between the `sass` (`dart-sass`) and `node-sass` op
|
|
|
321
349
|
|
|
322
350
|
Please consult documentation before using them:
|
|
323
351
|
|
|
324
|
-
- [Dart Sass documentation](https://
|
|
352
|
+
- [Dart Sass documentation](https://sass-lang.com/documentation/js-api/interfaces/Options) for all available `sass` options.
|
|
325
353
|
- [Node Sass documentation](https://github.com/sass/node-sass/#options) for all available `node-sass` options.
|
|
326
354
|
|
|
327
|
-
#### `
|
|
355
|
+
#### `object`
|
|
328
356
|
|
|
329
|
-
Use
|
|
357
|
+
Use an object for the Sass implementation setup.
|
|
330
358
|
|
|
331
359
|
**webpack.config.js**
|
|
332
360
|
|
|
@@ -355,7 +383,7 @@ module.exports = {
|
|
|
355
383
|
};
|
|
356
384
|
```
|
|
357
385
|
|
|
358
|
-
#### `
|
|
386
|
+
#### `function`
|
|
359
387
|
|
|
360
388
|
Allows to setup the Sass implementation by setting different options based on the loader context.
|
|
361
389
|
|
|
@@ -397,7 +425,12 @@ module.exports = {
|
|
|
397
425
|
|
|
398
426
|
### `sourceMap`
|
|
399
427
|
|
|
400
|
-
Type:
|
|
428
|
+
Type:
|
|
429
|
+
|
|
430
|
+
```ts
|
|
431
|
+
type sourceMap = boolean;
|
|
432
|
+
```
|
|
433
|
+
|
|
401
434
|
Default: depends on the `compiler.devtool` value
|
|
402
435
|
|
|
403
436
|
Enables/Disables generation of source maps.
|
|
@@ -469,7 +502,14 @@ module.exports = {
|
|
|
469
502
|
|
|
470
503
|
### `additionalData`
|
|
471
504
|
|
|
472
|
-
Type:
|
|
505
|
+
Type:
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
type additionalData =
|
|
509
|
+
| string
|
|
510
|
+
| ((content: string | Buffer, loaderContext: LoaderContext) => string);
|
|
511
|
+
```
|
|
512
|
+
|
|
473
513
|
Default: `undefined`
|
|
474
514
|
|
|
475
515
|
Prepends `Sass`/`SCSS` code before the actual entry file.
|
|
@@ -477,7 +517,7 @@ In this case, the `sass-loader` will not override the `data` option but just **p
|
|
|
477
517
|
|
|
478
518
|
This is especially useful when some of your Sass variables depend on the environment:
|
|
479
519
|
|
|
480
|
-
#### `
|
|
520
|
+
#### `string`
|
|
481
521
|
|
|
482
522
|
```js
|
|
483
523
|
module.exports = {
|
|
@@ -501,7 +541,7 @@ module.exports = {
|
|
|
501
541
|
};
|
|
502
542
|
```
|
|
503
543
|
|
|
504
|
-
#### `
|
|
544
|
+
#### `function`
|
|
505
545
|
|
|
506
546
|
##### Sync
|
|
507
547
|
|
|
@@ -573,7 +613,12 @@ module.exports = {
|
|
|
573
613
|
|
|
574
614
|
### `webpackImporter`
|
|
575
615
|
|
|
576
|
-
Type:
|
|
616
|
+
Type:
|
|
617
|
+
|
|
618
|
+
```ts
|
|
619
|
+
type webpackImporter = boolean;
|
|
620
|
+
```
|
|
621
|
+
|
|
577
622
|
Default: `true`
|
|
578
623
|
|
|
579
624
|
Enables/Disables the default Webpack importer.
|
|
@@ -607,7 +652,12 @@ module.exports = {
|
|
|
607
652
|
|
|
608
653
|
### `warnRuleAsWarning`
|
|
609
654
|
|
|
610
|
-
Type:
|
|
655
|
+
Type:
|
|
656
|
+
|
|
657
|
+
```ts
|
|
658
|
+
type warnRuleAsWarning = boolean;
|
|
659
|
+
```
|
|
660
|
+
|
|
611
661
|
Default: `false`
|
|
612
662
|
|
|
613
663
|
Treats the `@warn` rule as a webpack warning.
|
|
@@ -664,6 +714,49 @@ module.exports = {
|
|
|
664
714
|
};
|
|
665
715
|
```
|
|
666
716
|
|
|
717
|
+
### `api`
|
|
718
|
+
|
|
719
|
+
Type:
|
|
720
|
+
|
|
721
|
+
```ts
|
|
722
|
+
type api = "legacy" | "modern";
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
Default: `"legacy"`
|
|
726
|
+
|
|
727
|
+
Allows you to switch between `legacy` and `modern` API. You can find more information [here](https://sass-lang.com/documentation/js-api).
|
|
728
|
+
|
|
729
|
+
> ⚠ "modern" API is experimental, so some features may not work (known: built-in `importer` is not working and files with errors is not watching on initial run), you can follow this [here](https://github.com/webpack-contrib/sass-loader/issues/774).
|
|
730
|
+
|
|
731
|
+
> ⚠ The sass options are different for `modern` and `old` APIs. Please look at [docs](https://sass-lang.com/documentation/js-api) how to migrate on new options.
|
|
732
|
+
|
|
733
|
+
**webpack.config.js**
|
|
734
|
+
|
|
735
|
+
```js
|
|
736
|
+
module.exports = {
|
|
737
|
+
module: {
|
|
738
|
+
rules: [
|
|
739
|
+
{
|
|
740
|
+
test: /\.s[ac]ss$/i,
|
|
741
|
+
use: [
|
|
742
|
+
"style-loader",
|
|
743
|
+
"css-loader",
|
|
744
|
+
{
|
|
745
|
+
loader: "sass-loader",
|
|
746
|
+
options: {
|
|
747
|
+
api: "modern",
|
|
748
|
+
sassOptions: {
|
|
749
|
+
// Your sass options
|
|
750
|
+
},
|
|
751
|
+
},
|
|
752
|
+
},
|
|
753
|
+
],
|
|
754
|
+
},
|
|
755
|
+
],
|
|
756
|
+
},
|
|
757
|
+
};
|
|
758
|
+
```
|
|
759
|
+
|
|
667
760
|
## Examples
|
|
668
761
|
|
|
669
762
|
### Extracts CSS into separate files
|
package/dist/SassError.js
CHANGED
|
@@ -8,18 +8,20 @@ exports.default = void 0;
|
|
|
8
8
|
class SassError extends Error {
|
|
9
9
|
constructor(sassError) {
|
|
10
10
|
super();
|
|
11
|
-
this.name = "SassError";
|
|
11
|
+
this.name = "SassError";
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
if (typeof sassError.line !== "undefined" || typeof sassError.column !== "undefined") {
|
|
14
|
+
this.loc = {
|
|
15
|
+
line: sassError.line,
|
|
16
|
+
column: sassError.column
|
|
17
|
+
};
|
|
18
|
+
} // Keep original error if `sassError.formatted` is unavailable
|
|
18
19
|
|
|
19
|
-
this.message = `${this.name}: ${this.originalSassError.message}`;
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
this.message = `${this.name}: ${typeof sassError.message !== "undefined" ? sassError.message : sassError}`;
|
|
22
|
+
|
|
23
|
+
if (sassError.formatted) {
|
|
24
|
+
this.message = `${this.name}: ${sassError.formatted.replace(/^Error: /, "")}`; // Instruct webpack to hide the JS stack from the console.
|
|
23
25
|
// Usually you're only interested in the SASS stack in this case.
|
|
24
26
|
|
|
25
27
|
this.hideStack = true;
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
|
|
8
|
+
var _url = _interopRequireDefault(require("url"));
|
|
9
|
+
|
|
8
10
|
var _path = _interopRequireDefault(require("path"));
|
|
9
11
|
|
|
10
12
|
var _options = _interopRequireDefault(require("./options.json"));
|
|
@@ -36,31 +38,57 @@ async function loader(content) {
|
|
|
36
38
|
const shouldUseWebpackImporter = typeof options.webpackImporter === "boolean" ? options.webpackImporter : true;
|
|
37
39
|
|
|
38
40
|
if (shouldUseWebpackImporter) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const isModernAPI = options.api === "modern";
|
|
42
|
+
|
|
43
|
+
if (!isModernAPI) {
|
|
44
|
+
const {
|
|
45
|
+
includePaths
|
|
46
|
+
} = sassOptions;
|
|
47
|
+
sassOptions.importer.push((0, _utils.getWebpackImporter)(this, implementation, includePaths));
|
|
48
|
+
} else {
|
|
49
|
+
sassOptions.importers.push((0, _utils.getModernWebpackImporter)(this, implementation));
|
|
50
|
+
}
|
|
43
51
|
}
|
|
44
52
|
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const compile = (0, _utils.getCompileFn)(implementation, options);
|
|
54
|
+
let result;
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
result = await compile(sassOptions, options);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// There are situations when the `file`/`span.url` property do not exist
|
|
60
|
+
// Modern API
|
|
61
|
+
if (error.span && typeof error.span.url !== "undefined") {
|
|
62
|
+
this.addDependency(_url.default.fileURLToPath(error.span.url));
|
|
63
|
+
} // Legacy API
|
|
64
|
+
else if (typeof error.file !== "undefined") {
|
|
65
|
+
// `node-sass` returns POSIX paths
|
|
66
|
+
this.addDependency(_path.default.normalize(error.file));
|
|
56
67
|
}
|
|
57
68
|
|
|
58
|
-
|
|
69
|
+
callback(new _SassError.default(error));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let map = // Modern API, then legacy API
|
|
74
|
+
result.sourceMap ? result.sourceMap : result.map ? JSON.parse(result.map) : null; // Modify source paths only for webpack, otherwise we do nothing
|
|
75
|
+
|
|
76
|
+
if (map && useSourceMap) {
|
|
77
|
+
map = (0, _utils.normalizeSourceMap)(map, this.rootContext);
|
|
78
|
+
} // Modern API
|
|
59
79
|
|
|
60
|
-
if (map && useSourceMap) {
|
|
61
|
-
map = (0, _utils.normalizeSourceMap)(map, this.rootContext);
|
|
62
|
-
}
|
|
63
80
|
|
|
81
|
+
if (typeof result.loadedUrls !== "undefined") {
|
|
82
|
+
result.loadedUrls.forEach(includedFile => {
|
|
83
|
+
const normalizedIncludedFile = _url.default.fileURLToPath(includedFile); // Custom `importer` can return only `contents` so includedFile will be relative
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if (_path.default.isAbsolute(normalizedIncludedFile)) {
|
|
87
|
+
this.addDependency(normalizedIncludedFile);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
} // Legacy API
|
|
91
|
+
else if (typeof result.stats !== "undefined" && typeof result.stats.includedFiles !== "undefined") {
|
|
64
92
|
result.stats.includedFiles.forEach(includedFile => {
|
|
65
93
|
const normalizedIncludedFile = _path.default.normalize(includedFile); // Custom `importer` can return only `contents` so includedFile will be relative
|
|
66
94
|
|
|
@@ -69,8 +97,9 @@ async function loader(content) {
|
|
|
69
97
|
this.addDependency(normalizedIncludedFile);
|
|
70
98
|
}
|
|
71
99
|
});
|
|
72
|
-
|
|
73
|
-
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
callback(null, result.css.toString(), map);
|
|
74
103
|
}
|
|
75
104
|
|
|
76
105
|
var _default = loader;
|
package/dist/options.json
CHANGED
|
@@ -14,6 +14,11 @@
|
|
|
14
14
|
}
|
|
15
15
|
]
|
|
16
16
|
},
|
|
17
|
+
"api": {
|
|
18
|
+
"description": "Switch between old and modern API for `sass` (`Dart Sass`) and `Sass Embedded` implementations.",
|
|
19
|
+
"link": "https://github.com/webpack-contrib/sass-loader#sassoptions",
|
|
20
|
+
"enum": ["legacy", "modern"]
|
|
21
|
+
},
|
|
17
22
|
"sassOptions": {
|
|
18
23
|
"description": "Options for `node-sass` or `sass` (`Dart Sass`) implementation.",
|
|
19
24
|
"link": "https://github.com/webpack-contrib/sass-loader#sassoptions",
|
package/dist/utils.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.
|
|
6
|
+
exports.getCompileFn = getCompileFn;
|
|
7
|
+
exports.getModernWebpackImporter = getModernWebpackImporter;
|
|
7
8
|
exports.getSassImplementation = getSassImplementation;
|
|
8
9
|
exports.getSassOptions = getSassOptions;
|
|
9
10
|
exports.getWebpackImporter = getWebpackImporter;
|
|
@@ -28,13 +29,19 @@ function getDefaultSassImplementation() {
|
|
|
28
29
|
|
|
29
30
|
try {
|
|
30
31
|
require.resolve("sass");
|
|
31
|
-
} catch (
|
|
32
|
+
} catch (ignoreError) {
|
|
32
33
|
try {
|
|
33
34
|
require.resolve("node-sass");
|
|
34
35
|
|
|
35
36
|
sassImplPkg = "node-sass";
|
|
36
|
-
} catch (
|
|
37
|
-
|
|
37
|
+
} catch (_ignoreError) {
|
|
38
|
+
try {
|
|
39
|
+
require.resolve("sass-embedded");
|
|
40
|
+
|
|
41
|
+
sassImplPkg = "sass-embedded";
|
|
42
|
+
} catch (__ignoreError) {
|
|
43
|
+
sassImplPkg = "sass";
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
} // eslint-disable-next-line import/no-dynamic-require, global-require
|
|
40
47
|
|
|
@@ -93,6 +100,9 @@ function getSassImplementation(loaderContext, implementation) {
|
|
|
93
100
|
} else if (implementationName === "node-sass") {
|
|
94
101
|
// eslint-disable-next-line consistent-return
|
|
95
102
|
return resolvedImplementation;
|
|
103
|
+
} else if (implementationName === "sass-embedded") {
|
|
104
|
+
// eslint-disable-next-line consistent-return
|
|
105
|
+
return resolvedImplementation;
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
loaderContext.emitError(new Error(`Unknown Sass implementation "${implementationName}".`));
|
|
@@ -135,77 +145,11 @@ function isSupportedFibers() {
|
|
|
135
145
|
async function getSassOptions(loaderContext, loaderOptions, content, implementation, useSourceMap) {
|
|
136
146
|
const options = (0, _full.klona)(loaderOptions.sassOptions ? typeof loaderOptions.sassOptions === "function" ? loaderOptions.sassOptions(loaderContext) || {} : loaderOptions.sassOptions : {});
|
|
137
147
|
const isDartSass = implementation.info.includes("dart-sass");
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const shouldTryToResolveFibers = !options.fiber && options.fiber !== false;
|
|
141
|
-
|
|
142
|
-
if (shouldTryToResolveFibers) {
|
|
143
|
-
let fibers;
|
|
144
|
-
|
|
145
|
-
try {
|
|
146
|
-
fibers = require.resolve("fibers");
|
|
147
|
-
} catch (_error) {// Nothing
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (fibers) {
|
|
151
|
-
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
152
|
-
options.fiber = require(fibers);
|
|
153
|
-
}
|
|
154
|
-
} else if (options.fiber === false) {
|
|
155
|
-
// Don't pass the `fiber` option for `sass` (`Dart Sass`)
|
|
156
|
-
delete options.fiber;
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
// Don't pass the `fiber` option for `node-sass`
|
|
160
|
-
delete options.fiber;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
options.file = loaderContext.resourcePath;
|
|
164
|
-
options.data = loaderOptions.additionalData ? typeof loaderOptions.additionalData === "function" ? await loaderOptions.additionalData(content, loaderContext) : `${loaderOptions.additionalData}\n${content}` : content; // opt.outputStyle
|
|
165
|
-
|
|
166
|
-
if (!options.outputStyle && isProductionLikeMode(loaderContext)) {
|
|
167
|
-
options.outputStyle = "compressed";
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (useSourceMap) {
|
|
171
|
-
// Deliberately overriding the sourceMap option here.
|
|
172
|
-
// node-sass won't produce source maps if the data option is used and options.sourceMap is not a string.
|
|
173
|
-
// In case it is a string, options.sourceMap should be a path where the source map is written.
|
|
174
|
-
// But since we're using the data option, the source map will not actually be written, but
|
|
175
|
-
// all paths in sourceMap.sources will be relative to that path.
|
|
176
|
-
// Pretty complicated... :(
|
|
177
|
-
options.sourceMap = true;
|
|
178
|
-
options.outFile = _path.default.join(loaderContext.rootContext, "style.css.map");
|
|
179
|
-
options.sourceMapContents = true;
|
|
180
|
-
options.omitSourceMapUrl = true;
|
|
181
|
-
options.sourceMapEmbed = false;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const {
|
|
185
|
-
resourcePath
|
|
186
|
-
} = loaderContext;
|
|
187
|
-
|
|
188
|
-
const ext = _path.default.extname(resourcePath); // If we are compiling sass and indentedSyntax isn't set, automatically set it.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (ext && ext.toLowerCase() === ".sass" && typeof options.indentedSyntax === "undefined") {
|
|
192
|
-
options.indentedSyntax = true;
|
|
193
|
-
} else {
|
|
194
|
-
options.indentedSyntax = Boolean(options.indentedSyntax);
|
|
195
|
-
} // Allow passing custom importers to `sass`/`node-sass`. Accepts `Function` or an array of `Function`s.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
options.importer = options.importer ? proxyCustomImporters(Array.isArray(options.importer) ? options.importer : [options.importer], loaderContext) : [];
|
|
199
|
-
options.includePaths = [].concat(process.cwd()).concat( // We use `includePaths` in context for resolver, so it should be always absolute
|
|
200
|
-
(options.includePaths || []).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" ? ";" : ":") : []);
|
|
201
|
-
|
|
202
|
-
if (typeof options.charset === "undefined") {
|
|
203
|
-
options.charset = true;
|
|
204
|
-
}
|
|
148
|
+
const isModernAPI = loaderOptions.api === "modern";
|
|
149
|
+
options.data = loaderOptions.additionalData ? typeof loaderOptions.additionalData === "function" ? await loaderOptions.additionalData(content, loaderContext) : `${loaderOptions.additionalData}\n${content}` : content;
|
|
205
150
|
|
|
206
151
|
if (!options.logger) {
|
|
207
|
-
|
|
208
|
-
const needEmitWarning = loaderOptions.warnRuleAsWarning === true;
|
|
152
|
+
const needEmitWarning = loaderOptions.warnRuleAsWarning !== false;
|
|
209
153
|
const logger = loaderContext.getLogger("sass-loader");
|
|
210
154
|
|
|
211
155
|
const formatSpan = span => `${span.url || "-"}:${span.start.line}:${span.start.column}: `;
|
|
@@ -249,6 +193,100 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
|
|
|
249
193
|
};
|
|
250
194
|
}
|
|
251
195
|
|
|
196
|
+
const {
|
|
197
|
+
resourcePath
|
|
198
|
+
} = loaderContext;
|
|
199
|
+
|
|
200
|
+
if (isModernAPI) {
|
|
201
|
+
options.url = _url.default.pathToFileURL(resourcePath); // opt.outputStyle
|
|
202
|
+
|
|
203
|
+
if (!options.style && isProductionLikeMode(loaderContext)) {
|
|
204
|
+
options.style = "compressed";
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (useSourceMap) {
|
|
208
|
+
options.sourceMap = true;
|
|
209
|
+
} // If we are compiling sass and indentedSyntax isn't set, automatically set it.
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
if (typeof options.syntax === "undefined") {
|
|
213
|
+
const ext = _path.default.extname(resourcePath);
|
|
214
|
+
|
|
215
|
+
if (ext && ext.toLowerCase() === ".scss") {
|
|
216
|
+
options.syntax = "scss";
|
|
217
|
+
} else if (ext && ext.toLowerCase() === ".sass") {
|
|
218
|
+
options.syntax = "indented";
|
|
219
|
+
} else if (ext && ext.toLowerCase() === ".css") {
|
|
220
|
+
options.syntax = "css";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
options.importers = options.importers ? Array.isArray(options.importers) ? options.importers : [options.importers] : [];
|
|
225
|
+
} else {
|
|
226
|
+
options.file = resourcePath;
|
|
227
|
+
|
|
228
|
+
if (isDartSass && isSupportedFibers()) {
|
|
229
|
+
const shouldTryToResolveFibers = !options.fiber && options.fiber !== false;
|
|
230
|
+
|
|
231
|
+
if (shouldTryToResolveFibers) {
|
|
232
|
+
let fibers;
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
fibers = require.resolve("fibers");
|
|
236
|
+
} catch (_error) {// Nothing
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (fibers) {
|
|
240
|
+
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
241
|
+
options.fiber = require(fibers);
|
|
242
|
+
}
|
|
243
|
+
} else if (options.fiber === false) {
|
|
244
|
+
// Don't pass the `fiber` option for `sass` (`Dart Sass`)
|
|
245
|
+
delete options.fiber;
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
// Don't pass the `fiber` option for `node-sass`
|
|
249
|
+
delete options.fiber;
|
|
250
|
+
} // opt.outputStyle
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
if (!options.outputStyle && isProductionLikeMode(loaderContext)) {
|
|
254
|
+
options.outputStyle = "compressed";
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (useSourceMap) {
|
|
258
|
+
// Deliberately overriding the sourceMap option here.
|
|
259
|
+
// node-sass won't produce source maps if the data option is used and options.sourceMap is not a string.
|
|
260
|
+
// In case it is a string, options.sourceMap should be a path where the source map is written.
|
|
261
|
+
// But since we're using the data option, the source map will not actually be written, but
|
|
262
|
+
// all paths in sourceMap.sources will be relative to that path.
|
|
263
|
+
// Pretty complicated... :(
|
|
264
|
+
options.sourceMap = true;
|
|
265
|
+
options.outFile = _path.default.join(loaderContext.rootContext, "style.css.map");
|
|
266
|
+
options.sourceMapContents = true;
|
|
267
|
+
options.omitSourceMapUrl = true;
|
|
268
|
+
options.sourceMapEmbed = false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const ext = _path.default.extname(resourcePath); // If we are compiling sass and indentedSyntax isn't set, automatically set it.
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
if (ext && ext.toLowerCase() === ".sass" && typeof options.indentedSyntax === "undefined") {
|
|
275
|
+
options.indentedSyntax = true;
|
|
276
|
+
} else {
|
|
277
|
+
options.indentedSyntax = Boolean(options.indentedSyntax);
|
|
278
|
+
} // Allow passing custom importers to `sass`/`node-sass`. Accepts `Function` or an array of `Function`s.
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
options.importer = options.importer ? proxyCustomImporters(Array.isArray(options.importer) ? options.importer : [options.importer], loaderContext) : [];
|
|
282
|
+
options.includePaths = [].concat(process.cwd()).concat( // We use `includePaths` in context for resolver, so it should be always absolute
|
|
283
|
+
(options.includePaths || []).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" ? ";" : ":") : []);
|
|
284
|
+
|
|
285
|
+
if (typeof options.charset === "undefined") {
|
|
286
|
+
options.charset = true;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
252
290
|
return options;
|
|
253
291
|
}
|
|
254
292
|
|
|
@@ -330,6 +368,40 @@ function promiseResolve(callbackResolve) {
|
|
|
330
368
|
});
|
|
331
369
|
}
|
|
332
370
|
|
|
371
|
+
async function startResolving(resolutionMap) {
|
|
372
|
+
if (resolutionMap.length === 0) {
|
|
373
|
+
return Promise.reject();
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const [{
|
|
377
|
+
possibleRequests
|
|
378
|
+
}] = resolutionMap;
|
|
379
|
+
|
|
380
|
+
if (possibleRequests.length === 0) {
|
|
381
|
+
return Promise.reject();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const [{
|
|
385
|
+
resolve,
|
|
386
|
+
context
|
|
387
|
+
}] = resolutionMap;
|
|
388
|
+
|
|
389
|
+
try {
|
|
390
|
+
return await resolve(context, possibleRequests[0]);
|
|
391
|
+
} catch (_ignoreError) {
|
|
392
|
+
const [, ...tailResult] = possibleRequests;
|
|
393
|
+
|
|
394
|
+
if (tailResult.length === 0) {
|
|
395
|
+
const [, ...tailResolutionMap] = resolutionMap;
|
|
396
|
+
return startResolving(tailResolutionMap);
|
|
397
|
+
} // eslint-disable-next-line no-param-reassign
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
resolutionMap[0].possibleRequests = tailResult;
|
|
401
|
+
return startResolving(resolutionMap);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
333
405
|
const IS_SPECIAL_MODULE_IMPORT = /^~[^/]+$/; // `[drive_letter]:\` + `\\[server]\[sharename]\`
|
|
334
406
|
|
|
335
407
|
const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
|
|
@@ -352,41 +424,7 @@ const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
|
|
|
352
424
|
*/
|
|
353
425
|
|
|
354
426
|
function getWebpackResolver(resolverFactory, implementation, includePaths = []) {
|
|
355
|
-
|
|
356
|
-
if (resolutionMap.length === 0) {
|
|
357
|
-
return Promise.reject();
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
const [{
|
|
361
|
-
possibleRequests
|
|
362
|
-
}] = resolutionMap;
|
|
363
|
-
|
|
364
|
-
if (possibleRequests.length === 0) {
|
|
365
|
-
return Promise.reject();
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
const [{
|
|
369
|
-
resolve,
|
|
370
|
-
context
|
|
371
|
-
}] = resolutionMap;
|
|
372
|
-
|
|
373
|
-
try {
|
|
374
|
-
return await resolve(context, possibleRequests[0]);
|
|
375
|
-
} catch (_ignoreError) {
|
|
376
|
-
const [, ...tailResult] = possibleRequests;
|
|
377
|
-
|
|
378
|
-
if (tailResult.length === 0) {
|
|
379
|
-
const [, ...tailResolutionMap] = resolutionMap;
|
|
380
|
-
return startResolving(tailResolutionMap);
|
|
381
|
-
} // eslint-disable-next-line no-param-reassign
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
resolutionMap[0].possibleRequests = tailResult;
|
|
385
|
-
return startResolving(resolutionMap);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const isDartSass = implementation.info.includes("dart-sass"); // We only have one difference with the built-in sass resolution logic and out resolution logic:
|
|
427
|
+
const isDartSass = implementation && implementation.info.includes("dart-sass"); // We only have one difference with the built-in sass resolution logic and out resolution logic:
|
|
390
428
|
// First, we look at the files starting with `_`, then without `_` (i.e. `_name.sass`, `_name.scss`, `_name.css`, `name.sass`, `name.scss`, `name.css`),
|
|
391
429
|
// although `sass` look together by extensions (i.e. `_name.sass`/`name.sass`/`_name.scss`/`name.scss`/`_name.css`/`name.css`).
|
|
392
430
|
// It shouldn't be a problem because `sass` throw errors:
|
|
@@ -510,6 +548,18 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
|
|
|
510
548
|
|
|
511
549
|
const MATCH_CSS = /\.css$/i;
|
|
512
550
|
|
|
551
|
+
function getModernWebpackImporter() {
|
|
552
|
+
return {
|
|
553
|
+
async canonicalize() {
|
|
554
|
+
return null;
|
|
555
|
+
},
|
|
556
|
+
|
|
557
|
+
load() {// TODO implement
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
513
563
|
function getWebpackImporter(loaderContext, implementation, includePaths) {
|
|
514
564
|
const resolve = getWebpackResolver(loaderContext.getResolve, implementation, includePaths);
|
|
515
565
|
return function importer(originalUrl, prev, done) {
|
|
@@ -539,14 +589,38 @@ let nodeSassJobQueue = null;
|
|
|
539
589
|
* Verifies that the implementation and version of Sass is supported by this loader.
|
|
540
590
|
*
|
|
541
591
|
* @param {Object} implementation
|
|
592
|
+
* @param {Object} options
|
|
542
593
|
* @returns {Function}
|
|
543
594
|
*/
|
|
544
595
|
|
|
545
|
-
function
|
|
546
|
-
const
|
|
596
|
+
function getCompileFn(implementation, options) {
|
|
597
|
+
const isNewSass = implementation.info.includes("dart-sass") || implementation.info.includes("sass-embedded");
|
|
598
|
+
|
|
599
|
+
if (isNewSass) {
|
|
600
|
+
if (options.api === "modern") {
|
|
601
|
+
return sassOptions => {
|
|
602
|
+
const {
|
|
603
|
+
data,
|
|
604
|
+
...rest
|
|
605
|
+
} = sassOptions;
|
|
606
|
+
return implementation.compileStringAsync(data, rest);
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
return sassOptions => new Promise((resolve, reject) => {
|
|
611
|
+
implementation.render(sassOptions, (error, result) => {
|
|
612
|
+
if (error) {
|
|
613
|
+
reject(error);
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
resolve(result);
|
|
618
|
+
});
|
|
619
|
+
});
|
|
620
|
+
}
|
|
547
621
|
|
|
548
|
-
if (
|
|
549
|
-
|
|
622
|
+
if (options.api === "modern") {
|
|
623
|
+
throw new Error("Modern API is not supported for 'node-sass'");
|
|
550
624
|
} // There is an issue with node-sass when async custom importers are used
|
|
551
625
|
// See https://github.com/sass/node-sass/issues/857#issuecomment-93594360
|
|
552
626
|
// We need to use a job queue to make sure that one thread is always available to the UV lib
|
|
@@ -557,7 +631,16 @@ function getRenderFunctionFromSassImplementation(implementation) {
|
|
|
557
631
|
nodeSassJobQueue = _neoAsync.default.queue(implementation.render.bind(implementation), threadPoolSize - 1);
|
|
558
632
|
}
|
|
559
633
|
|
|
560
|
-
return
|
|
634
|
+
return sassOptions => new Promise((resolve, reject) => {
|
|
635
|
+
nodeSassJobQueue.push.bind(nodeSassJobQueue)(sassOptions, (error, result) => {
|
|
636
|
+
if (error) {
|
|
637
|
+
reject(error);
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
resolve(result);
|
|
642
|
+
});
|
|
643
|
+
});
|
|
561
644
|
}
|
|
562
645
|
|
|
563
646
|
const ABSOLUTE_SCHEME = /^[A-Za-z0-9+\-.]+:/;
|
|
@@ -587,7 +670,10 @@ function normalizeSourceMap(map, rootContext) {
|
|
|
587
670
|
// Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it.
|
|
588
671
|
// eslint-disable-next-line no-param-reassign
|
|
589
672
|
|
|
590
|
-
|
|
673
|
+
if (typeof newMap.file !== "undefined") {
|
|
674
|
+
delete newMap.file;
|
|
675
|
+
} // eslint-disable-next-line no-param-reassign
|
|
676
|
+
|
|
591
677
|
|
|
592
678
|
newMap.sourceRoot = ""; // node-sass returns POSIX paths, that's why we need to transform them back to native paths.
|
|
593
679
|
// This fixes an error on windows where the source-map module cannot resolve the source maps.
|
|
@@ -595,9 +681,11 @@ function normalizeSourceMap(map, rootContext) {
|
|
|
595
681
|
// eslint-disable-next-line no-param-reassign
|
|
596
682
|
|
|
597
683
|
newMap.sources = newMap.sources.map(source => {
|
|
598
|
-
const sourceType = getURLType(source); // Do no touch `scheme-relative`, `path-absolute` and `absolute` types
|
|
684
|
+
const sourceType = getURLType(source); // Do no touch `scheme-relative`, `path-absolute` and `absolute` types (except `file:`)
|
|
599
685
|
|
|
600
|
-
if (sourceType === "
|
|
686
|
+
if (sourceType === "absolute" && /^file:/i.test(source)) {
|
|
687
|
+
return _url.default.fileURLToPath(source);
|
|
688
|
+
} else if (sourceType === "path-relative") {
|
|
601
689
|
return _path.default.resolve(rootContext, _path.default.normalize(source));
|
|
602
690
|
}
|
|
603
691
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sass-loader",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "13.0.0",
|
|
4
4
|
"description": "Sass loader for webpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "webpack-contrib/sass-loader",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
},
|
|
14
14
|
"main": "dist/cjs.js",
|
|
15
15
|
"engines": {
|
|
16
|
-
"node": ">=
|
|
16
|
+
"node": ">= 14.15.0"
|
|
17
17
|
},
|
|
18
18
|
"scripts": {
|
|
19
19
|
"start": "npm run build -- -w",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"fibers": ">= 3.1.0",
|
|
42
42
|
"node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0",
|
|
43
43
|
"sass": "^1.3.0",
|
|
44
|
+
"sass-embedded": "*",
|
|
44
45
|
"webpack": "^5.0.0"
|
|
45
46
|
},
|
|
46
47
|
"peerDependenciesMeta": {
|
|
@@ -50,6 +51,9 @@
|
|
|
50
51
|
"sass": {
|
|
51
52
|
"optional": true
|
|
52
53
|
},
|
|
54
|
+
"sass-embedded": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
53
57
|
"fibers": {
|
|
54
58
|
"optional": true
|
|
55
59
|
}
|
|
@@ -59,41 +63,43 @@
|
|
|
59
63
|
"neo-async": "^2.6.2"
|
|
60
64
|
},
|
|
61
65
|
"devDependencies": {
|
|
62
|
-
"@babel/cli": "^7.
|
|
63
|
-
"@babel/core": "^7.
|
|
64
|
-
"@babel/preset-env": "^7.
|
|
65
|
-
"@commitlint/cli": "^
|
|
66
|
-
"@commitlint/config-conventional": "^
|
|
66
|
+
"@babel/cli": "^7.17.10",
|
|
67
|
+
"@babel/core": "^7.17.10",
|
|
68
|
+
"@babel/preset-env": "^7.17.10",
|
|
69
|
+
"@commitlint/cli": "^17.0.0",
|
|
70
|
+
"@commitlint/config-conventional": "^17.0.0",
|
|
67
71
|
"@webpack-contrib/eslint-config-webpack": "^3.0.0",
|
|
68
|
-
"babel-jest": "^
|
|
72
|
+
"babel-jest": "^28.1.0",
|
|
69
73
|
"bootstrap-sass": "^3.4.1",
|
|
70
74
|
"bootstrap-v4": "npm:bootstrap@^4.5.3",
|
|
71
75
|
"bootstrap-v5": "npm:bootstrap@^5.0.1",
|
|
72
76
|
"cross-env": "^7.0.3",
|
|
73
|
-
"css-loader": "^6.
|
|
77
|
+
"css-loader": "^6.6.0",
|
|
74
78
|
"del": "^6.0.0",
|
|
75
79
|
"del-cli": "^4.0.1",
|
|
76
80
|
"enhanced-resolve": "^5.8.2",
|
|
77
|
-
"eslint": "^8.
|
|
81
|
+
"eslint": "^8.15.0",
|
|
78
82
|
"eslint-config-prettier": "^8.3.0",
|
|
79
|
-
"eslint-plugin-import": "^2.
|
|
80
|
-
"fibers": "^5.0.
|
|
83
|
+
"eslint-plugin-import": "^2.25.4",
|
|
84
|
+
"fibers": "^5.0.1",
|
|
81
85
|
"file-loader": "^6.2.0",
|
|
82
86
|
"foundation-sites": "^6.6.3",
|
|
83
|
-
"husky": "^
|
|
84
|
-
"jest": "^
|
|
85
|
-
"
|
|
87
|
+
"husky": "^8.0.1",
|
|
88
|
+
"jest": "^28.1.0",
|
|
89
|
+
"jest-environment-node-single-context": "^28.0.0",
|
|
90
|
+
"lint-staged": "^12.4.1",
|
|
86
91
|
"material-components-web": "^8.0.0",
|
|
87
|
-
"memfs": "^3.
|
|
88
|
-
"node-sass": "^7.0.
|
|
92
|
+
"memfs": "^3.4.1",
|
|
93
|
+
"node-sass": "^7.0.1",
|
|
89
94
|
"node-sass-glob-importer": "^5.3.2",
|
|
90
95
|
"npm-run-all": "^4.1.5",
|
|
91
96
|
"prettier": "^2.3.2",
|
|
92
|
-
"sass": "^1.
|
|
97
|
+
"sass": "^1.51.0",
|
|
98
|
+
"sass-embedded": "^1.51.0",
|
|
93
99
|
"semver": "^7.3.5",
|
|
94
100
|
"standard-version": "^9.3.1",
|
|
95
101
|
"style-loader": "^3.2.1",
|
|
96
|
-
"webpack": "^5.
|
|
102
|
+
"webpack": "^5.72.1"
|
|
97
103
|
},
|
|
98
104
|
"keywords": [
|
|
99
105
|
"sass",
|