sass-loader 12.2.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,17 +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. |
136
+ - **[`implementation`](#implementation)**
137
+ - **[`sassOptions`](#sassoptions)**
138
+ - **[`sourceMap`](#sourcemap)**
139
+ - **[`additionalData`](#additionaldata)**
140
+ - **[`webpackImporter`](#webpackimporter)**
141
+ - **[`warnRuleAsWarning`](#warnruleaswarning)**
129
142
 
130
143
  ### `implementation`
131
144
 
132
- Type: `Object | String`
145
+ Type:
146
+
147
+ ```ts
148
+ type implementation = object | string;
149
+ ```
150
+
133
151
  Default: `sass`
134
152
 
135
153
  The special `implementation` option determines which implementation of Sass to use.
@@ -168,7 +186,7 @@ In order to avoid this situation you can use the `implementation` option.
168
186
 
169
187
  The `implementation` options either accepts `sass` (`Dart Sass`) or `node-sass` as a module.
170
188
 
171
- #### Object
189
+ #### `object`
172
190
 
173
191
  For example, to use Dart Sass, you'd pass:
174
192
 
@@ -195,7 +213,7 @@ module.exports = {
195
213
  };
196
214
  ```
197
215
 
198
- #### String
216
+ #### `string`
199
217
 
200
218
  For example, to use Dart Sass, you'd pass:
201
219
 
@@ -301,7 +319,18 @@ module.exports = {
301
319
 
302
320
  ### `sassOptions`
303
321
 
304
- 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
+
305
334
  Default: defaults values for Sass implementation
306
335
 
307
336
  Options for [Dart Sass](http://sass-lang.com/dart-sass) or [Node Sass](https://github.com/sass/node-sass) implementation.
@@ -323,9 +352,9 @@ Please consult documentation before using them:
323
352
  - [Dart Sass documentation](https://github.com/sass/dart-sass#javascript-api) for all available `sass` options.
324
353
  - [Node Sass documentation](https://github.com/sass/node-sass/#options) for all available `node-sass` options.
325
354
 
326
- #### `Object`
355
+ #### `object`
327
356
 
328
- Use and object for the Sass implementation setup.
357
+ Use an object for the Sass implementation setup.
329
358
 
330
359
  **webpack.config.js**
331
360
 
@@ -354,7 +383,7 @@ module.exports = {
354
383
  };
355
384
  ```
356
385
 
357
- #### `Function`
386
+ #### `function`
358
387
 
359
388
  Allows to setup the Sass implementation by setting different options based on the loader context.
360
389
 
@@ -396,7 +425,12 @@ module.exports = {
396
425
 
397
426
  ### `sourceMap`
398
427
 
399
- Type: `Boolean`
428
+ Type:
429
+
430
+ ```ts
431
+ type sourceMap = boolean;
432
+ ```
433
+
400
434
  Default: depends on the `compiler.devtool` value
401
435
 
402
436
  Enables/Disables generation of source maps.
@@ -468,7 +502,14 @@ module.exports = {
468
502
 
469
503
  ### `additionalData`
470
504
 
471
- Type: `String|Function`
505
+ Type:
506
+
507
+ ```ts
508
+ type additionalData =
509
+ | string
510
+ | ((content: string | Buffer, loaderContext: LoaderContext) => string);
511
+ ```
512
+
472
513
  Default: `undefined`
473
514
 
474
515
  Prepends `Sass`/`SCSS` code before the actual entry file.
@@ -476,7 +517,7 @@ In this case, the `sass-loader` will not override the `data` option but just **p
476
517
 
477
518
  This is especially useful when some of your Sass variables depend on the environment:
478
519
 
479
- #### `String`
520
+ #### `string`
480
521
 
481
522
  ```js
482
523
  module.exports = {
@@ -500,7 +541,7 @@ module.exports = {
500
541
  };
501
542
  ```
502
543
 
503
- #### `Function`
544
+ #### `function`
504
545
 
505
546
  ##### Sync
506
547
 
@@ -572,7 +613,12 @@ module.exports = {
572
613
 
573
614
  ### `webpackImporter`
574
615
 
575
- Type: `Boolean`
616
+ Type:
617
+
618
+ ```ts
619
+ type webpackImporter = boolean;
620
+ ```
621
+
576
622
  Default: `true`
577
623
 
578
624
  Enables/Disables the default Webpack importer.
@@ -604,6 +650,113 @@ module.exports = {
604
650
  };
605
651
  ```
606
652
 
653
+ ### `warnRuleAsWarning`
654
+
655
+ Type:
656
+
657
+ ```ts
658
+ type warnRuleAsWarning = boolean;
659
+ ```
660
+
661
+ Default: `false`
662
+
663
+ Treats the `@warn` rule as a webpack warning.
664
+
665
+ > ℹ️ It will be `true` by default in the next major release.
666
+
667
+ **style.scss**
668
+
669
+ ```scss
670
+ $known-prefixes: webkit, moz, ms, o;
671
+
672
+ @mixin prefix($property, $value, $prefixes) {
673
+ @each $prefix in $prefixes {
674
+ @if not index($known-prefixes, $prefix) {
675
+ @warn "Unknown prefix #{$prefix}.";
676
+ }
677
+
678
+ -#{$prefix}-#{$property}: $value;
679
+ }
680
+ #{$property}: $value;
681
+ }
682
+
683
+ .tilt {
684
+ // Oops, we typo'd "webkit" as "wekbit"!
685
+ @include prefix(transform, rotate(15deg), wekbit ms);
686
+ }
687
+ ```
688
+
689
+ The presented code will throw webpack warning instead logging.
690
+
691
+ To ignore unnecessary warnings you can use the [ignoreWarnings](https://webpack.js.org/configuration/other-options/#ignorewarnings) option.
692
+
693
+ **webpack.config.js**
694
+
695
+ ```js
696
+ module.exports = {
697
+ module: {
698
+ rules: [
699
+ {
700
+ test: /\.s[ac]ss$/i,
701
+ use: [
702
+ "style-loader",
703
+ "css-loader",
704
+ {
705
+ loader: "sass-loader",
706
+ options: {
707
+ warnRuleAsWarning: true,
708
+ },
709
+ },
710
+ ],
711
+ },
712
+ ],
713
+ },
714
+ };
715
+ ```
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
+
607
760
  ## Examples
608
761
 
609
762
  ### Extracts CSS into separate files
package/dist/SassError.js CHANGED
@@ -8,14 +8,19 @@ 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"; // TODO remove me in the next major release
12
+
12
13
  this.originalSassError = sassError;
13
- this.loc = {
14
- line: sassError.line,
15
- column: sassError.column
16
- }; // Keep original error if `sassError.formatted` is unavailable
17
14
 
18
- 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}`;
19
24
 
20
25
  if (this.originalSassError.formatted) {
21
26
  this.message = `${this.name}: ${this.originalSassError.formatted.replace(/^Error: /, "")}`; // Instruct webpack to hide the JS stack from the console.
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ class SassWarning extends Error {
9
+ constructor(warning, options) {
10
+ super(warning);
11
+ this.name = "SassWarning";
12
+ this.hideStack = true;
13
+
14
+ if (options.span) {
15
+ this.loc = {
16
+ line: options.span.start.line,
17
+ column: options.span.start.column
18
+ };
19
+ }
20
+ }
21
+
22
+ }
23
+
24
+ var _default = SassWarning;
25
+ exports.default = _default;
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",
@@ -48,6 +53,11 @@
48
53
  "description": "Enables/Disables default `webpack` importer.",
49
54
  "link": "https://github.com/webpack-contrib/sass-loader#webpackimporter",
50
55
  "type": "boolean"
56
+ },
57
+ "warnRuleAsWarning": {
58
+ "description": "Treats the '@warn' rule as a webpack warning.",
59
+ "link": "https://github.com/webpack-contrib/sass-loader#warnruleaswarning",
60
+ "type": "boolean"
51
61
  }
52
62
  },
53
63
  "additionalProperties": false