sass-loader 12.4.0 → 12.6.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 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
- `sass-loader` requires you to install either [Dart Sass](https://github.com/sass/dart-sass) or [Node Sass](https://github.com/sass/node-sass) on your own (more documentation can be found below).
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
- | Name | Type | Default | Description |
123
- | :-------------------------------------------: | :------------------: | :-------------------------------------: | :---------------------------------------------------------------- |
124
- | **[`implementation`](#implementation)** | `{Object\|String}` | `sass` | Setup Sass implementation to use. |
125
- | **[`sassOptions`](#sassoptions)** | `{Object\|Function}` | defaults values for Sass implementation | Options for Sass. |
126
- | **[`sourceMap`](#sourcemap)** | `{Boolean}` | `compiler.devtool` | Enables/Disables generation of source maps. |
127
- | **[`additionalData`](#additionaldata)** | `{String\|Function}` | `undefined` | Prepends/Appends `Sass`/`SCSS` code before the actual entry file. |
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: `Object | String`
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
- #### Object
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
- #### String
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: `Object|Function`
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.
@@ -324,9 +352,9 @@ Please consult documentation before using them:
324
352
  - [Dart Sass documentation](https://github.com/sass/dart-sass#javascript-api) 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
- #### `Object`
355
+ #### `object`
328
356
 
329
- Use and object for the Sass implementation setup.
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
- #### `Function`
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: `Boolean`
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: `String|Function`
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
- #### `String`
520
+ #### `string`
481
521
 
482
522
  ```js
483
523
  module.exports = {
@@ -501,7 +541,7 @@ module.exports = {
501
541
  };
502
542
  ```
503
543
 
504
- #### `Function`
544
+ #### `function`
505
545
 
506
546
  ##### Sync
507
547
 
@@ -573,7 +613,12 @@ module.exports = {
573
613
 
574
614
  ### `webpackImporter`
575
615
 
576
- Type: `Boolean`
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: `Boolean`
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
@@ -11,12 +11,16 @@ class SassError extends Error {
11
11
  this.name = "SassError"; // TODO remove me in the next major release
12
12
 
13
13
  this.originalSassError = sassError;
14
- this.loc = {
15
- line: sassError.line,
16
- column: sassError.column
17
- }; // Keep original error if `sassError.formatted` is unavailable
18
14
 
19
- this.message = `${this.name}: ${this.originalSassError.message}`;
15
+ if (typeof sassError.line !== "undefined" || typeof sassError.column !== "undefined") {
16
+ this.loc = {
17
+ line: sassError.line,
18
+ column: sassError.column
19
+ };
20
+ } // Keep original error if `sassError.formatted` is unavailable
21
+
22
+
23
+ this.message = `${this.name}: ${typeof this.originalSassError.message !== "undefined" ? this.originalSassError.message : this.originalSassError}`;
20
24
 
21
25
  if (this.originalSassError.formatted) {
22
26
  this.message = `${this.name}: ${this.originalSassError.formatted.replace(/^Error: /, "")}`; // Instruct webpack to hide the JS stack from the console.
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
- includePaths
41
- } = sassOptions;
42
- sassOptions.importer.push((0, _utils.getWebpackImporter)(this, implementation, includePaths));
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 render = (0, _utils.getRenderFunctionFromSassImplementation)(implementation);
46
- render(sassOptions, (error, result) => {
47
- if (error) {
48
- // There are situations when the `file` property do not exist
49
- if (error.file) {
50
- // `node-sass` returns POSIX paths
51
- this.addDependency(_path.default.normalize(error.file));
52
- }
53
-
54
- callback(new _SassError.default(error));
55
- return;
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
- let map = result.map ? JSON.parse(result.map) : null; // Modify source paths only for webpack, otherwise we do nothing
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
- callback(null, result.css.toString(), map);
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",