sass-loader 16.0.4 → 16.0.6

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
@@ -13,6 +13,7 @@
13
13
  [![coverage][cover]][cover-url]
14
14
  [![discussion][discussion]][discussion-url]
15
15
  [![size][size]][size-url]
16
+ [![discord-invite][discord-invite]][discord-url]
16
17
 
17
18
  # sass-loader
18
19
 
@@ -44,7 +45,7 @@ pnpm add -D sass-loader sass webpack
44
45
 
45
46
  `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).
46
47
 
47
- This allows you to control the versions of all your dependencies, and to choose which Sass implementation to use.
48
+ This allows you to control the versions of all your dependencies and to choose which Sass implementation to use.
48
49
 
49
50
  > [!NOTE]
50
51
  >
@@ -54,7 +55,7 @@ This allows you to control the versions of all your dependencies, and to choose
54
55
  >
55
56
  > [Node Sass](https://github.com/sass/node-sass) does not work with [Yarn PnP](https://classic.yarnpkg.com/en/docs/pnp/) and doesn't support [@use rule](https://sass-lang.com/documentation/at-rules/use).
56
57
 
57
- 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.
58
+ Chain the `sass-loader` with the [css-loader](https://github.com/webpack/css-loader) and the [style-loader](https://github.com/webpack/style-loader) to immediately apply all styles to the DOM, or with the [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin) to extract it into a separate file.
58
59
 
59
60
  Then add the loader to your webpack configuration. For example:
60
61
 
@@ -96,7 +97,7 @@ module.exports = {
96
97
  };
97
98
  ```
98
99
 
99
- Finally run `webpack` via your preferred method.
100
+ Finally run `webpack` via your preferred method (e.g., via CLI or an npm script).
100
101
 
101
102
  ### The `style` (new API, by default since 16 version) and `outputStyle` (old API) options in `production` mode
102
103
 
@@ -106,13 +107,14 @@ For `production` mode, the `style` (new API, by default since 16 version) and `o
106
107
 
107
108
  Webpack provides an [advanced mechanism to resolve files](https://webpack.js.org/concepts/module-resolution/).
108
109
 
109
- The `sass-loader` uses Sass's custom importer feature to pass all queries to the webpack resolving engine enabling you to import your Sass modules from `node_modules`.
110
+ The `sass-loader` uses Sass's custom importer feature to pass all queries to the webpack resolving engine, enabling you to import your Sass modules from `node_modules`.
110
111
 
111
112
  ```scss
112
113
  @import "bootstrap";
113
114
  ```
114
115
 
115
116
  Using `~` is deprecated and should be removed from your code, but we still support it for historical reasons.
117
+
116
118
  Why can you remove it? The loader will first try to resolve `@import` as a relative path. If it cannot be resolved, then the loader will try to resolve `@import` inside [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules).
117
119
 
118
120
  Prepending module paths with a `~` tells webpack to search through [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules).
@@ -122,22 +124,25 @@ Prepending module paths with a `~` tells webpack to search through [`node_module
122
124
  ```
123
125
 
124
126
  It's important to prepend the path with only `~`, because `~/` resolves to the home directory.
127
+
125
128
  Webpack needs to distinguish between `bootstrap` and `~bootstrap` because CSS and Sass files have no special syntax for importing relative files.
129
+
126
130
  Writing `@import "style.scss"` is the same as `@import "./style.scss";`
127
131
 
128
132
  ### Problems with `url(...)`
129
133
 
130
134
  Since Sass implementations don't provide [url rewriting](https://github.com/sass/libsass/issues/532), all linked assets must be relative to the output.
131
135
 
132
- - If you pass the generated CSS on to the `css-loader`, all urls must be relative to the entry-file (e.g. `main.scss`).
133
- - If you're just generating CSS without passing it to the `css-loader`, it must be relative to your web root.
136
+ - If you pass the generated CSS on to the `css-loader`, all URLs must be relative to the entry-file (e.g. `main.scss`).
137
+ - If you're just generating CSS without passing it to the `css-loader`, URLs must be relative to your web root.
134
138
 
135
139
  You might be surprised by this first issue, as it is natural to expect relative references to be resolved against the `.sass`/`.scss` file in which they are specified (like in regular `.css` files).
136
140
 
137
141
  Thankfully there are two solutions to this problem:
138
142
 
139
- - Add the missing url rewriting using the [resolve-url-loader](https://github.com/bholloway/resolve-url-loader). Place it before `sass-loader` in the loader chain.
140
- - Library authors usually provide a variable to modify the asset path. [bootstrap-sass](https://github.com/twbs/bootstrap-sass) for example has an `$icon-font-path`.
143
+ - Add the missing URL rewriting using the [resolve-url-loader](https://github.com/bholloway/resolve-url-loader). Place it before `sass-loader` in the loader chain.
144
+
145
+ - Library authors usually provide a variable to modify the asset path. [bootstrap-sass](https://github.com/twbs/bootstrap-sass) for example, has an `$icon-font-path`.
141
146
 
142
147
  ## Options
143
148
 
@@ -164,7 +169,7 @@ The special `implementation` option determines which implementation of Sass to u
164
169
  By default, the loader resolves the implementation based on your dependencies.
165
170
  Just add the desired implementation to your `package.json` (`sass`, `sass-embedded`, or `node-sass` package) and install dependencies.
166
171
 
167
- Example where the `sass-loader` loader uses the `sass` (`dart-sass`) implementation:
172
+ Example where the `sass-loader` uses the `sass` (`dart-sass`) implementation:
168
173
 
169
174
  **package.json**
170
175
 
@@ -177,7 +182,7 @@ Example where the `sass-loader` loader uses the `sass` (`dart-sass`) implementat
177
182
  }
178
183
  ```
179
184
 
180
- Example where the `sass-loader` loader uses the `node-sass` implementation:
185
+ Example where the `sass-loader` uses the `node-sass` implementation:
181
186
 
182
187
  **package.json**
183
188
 
@@ -190,7 +195,7 @@ Example where the `sass-loader` loader uses the `node-sass` implementation:
190
195
  }
191
196
  ```
192
197
 
193
- Example where the `sass-loader` loader uses the `sass-embedded` implementation:
198
+ Example where the `sass-loader` uses the `sass-embedded` implementation:
194
199
 
195
200
  **package.json**
196
201
 
@@ -208,8 +213,7 @@ Example where the `sass-loader` loader uses the `sass-embedded` implementation:
208
213
 
209
214
  > [!NOTE]
210
215
  >
211
- > Using `optionalDependencies` means that `sass-loader` can fallback to `sass`
212
- > when running on an operating system not supported by `sass-embedded`
216
+ > Using `optionalDependencies` means that `sass-loader` can fallback to `sass` when running on an operating system not supported by `sass-embedded`
213
217
 
214
218
  Be aware of the order that `sass-loader` will resolve the implementation:
215
219
 
@@ -221,7 +225,7 @@ You can specify a specific implementation by using the `implementation` option,
221
225
 
222
226
  #### `object`
223
227
 
224
- For example, to always use Dart Sass, you'd pass:
228
+ For example, to always use `Dart Sass`, you'd pass:
225
229
 
226
230
  ```js
227
231
  module.exports = {
@@ -293,11 +297,11 @@ Options for [Dart Sass](http://sass-lang.com/dart-sass) or [Node Sass](https://g
293
297
 
294
298
  > [!NOTE]
295
299
  >
296
- > The `charset` option is `true` by default for `dart-sass`, we strongly discourage setting this to `false`, because webpack doesn't support files other than `utf-8`.
300
+ > The `charset` option is `true` by default for `dart-sass`. We strongly discourage setting this to `false` because webpack doesn't support files other than `utf-8`.
297
301
 
298
302
  > [!NOTE]
299
303
  >
300
- > The `syntax` (new API, by default since 16 version)`and`indentedSyntax`(old API) option is`scss`for the`scss`extension,`indented`for the`sass`extension and`css`for the`css` extension.
304
+ > The `syntax` (new API, by default since 16 version) and `indentedSyntax` (old API) option is `scss` for the `scss` extension, `indented` for the `sass` extension, and `css` for the `css` extension.
301
305
 
302
306
  > [!NOTE]
303
307
  >
@@ -336,7 +340,7 @@ module.exports = {
336
340
  loader: "sass-loader",
337
341
  options: {
338
342
  sassOptions: {
339
- style: `compressed`,
343
+ style: "compressed",
340
344
  loadPaths: ["absolute/path/a", "absolute/path/b"],
341
345
  },
342
346
  },
@@ -398,7 +402,7 @@ type sourceMap = boolean;
398
402
 
399
403
  Default: depends on the `compiler.devtool` value
400
404
 
401
- Enables/Disables generation of source maps.
405
+ Enables/disables generation of source maps.
402
406
 
403
407
  By default generation of source maps depends on the [`devtool`](https://webpack.js.org/configuration/devtool/) option.
404
408
  All values enable source map generation except `eval` and `false`.
@@ -434,9 +438,9 @@ module.exports = {
434
438
  };
435
439
  ```
436
440
 
437
- > ℹ In some rare cases `node-sass` can output invalid source maps (it is a `node-sass` bug).
441
+ > ℹ In some rare cases `node-sass` can output invalid source maps (this is a `node-sass` bug).
438
442
  >
439
- > In order to avoid this, you can try to update `node-sass` to latest version, or you can try to set within `sassOptions` the `outputStyle` option to `compressed`.
443
+ > In order to avoid this, you can try to update `node-sass` to the latest version, or you can try to set within `sassOptions` the `outputStyle` option to `compressed`.
440
444
 
441
445
  **webpack.config.js**
442
446
 
@@ -496,7 +500,7 @@ module.exports = {
496
500
  {
497
501
  loader: "sass-loader",
498
502
  options: {
499
- additionalData: "$env: " + process.env.NODE_ENV + ";",
503
+ additionalData: `$env: ${process.env.NODE_ENV};`,
500
504
  },
501
505
  },
502
506
  ],
@@ -528,10 +532,10 @@ module.exports = {
528
532
  const relativePath = path.relative(rootContext, resourcePath);
529
533
 
530
534
  if (relativePath === "styles/foo.scss") {
531
- return "$value: 100px;" + content;
535
+ return `$value: 100px;${content}`;
532
536
  }
533
537
 
534
- return "$value: 200px;" + content;
538
+ return `$value: 200px;${content}`;
535
539
  },
536
540
  },
537
541
  },
@@ -562,10 +566,10 @@ module.exports = {
562
566
  const relativePath = path.relative(rootContext, resourcePath);
563
567
 
564
568
  if (relativePath === "styles/foo.scss") {
565
- return "$value: 100px;" + content;
569
+ return `$value: 100px;${content}`;
566
570
  }
567
571
 
568
- return "$value: 200px;" + content;
572
+ return `$value: 200px;${content}`;
569
573
  },
570
574
  },
571
575
  },
@@ -586,10 +590,10 @@ type webpackImporter = boolean;
586
590
 
587
591
  Default: `true`
588
592
 
589
- Enables/Disables the default webpack importer.
593
+ Enables/disables the default webpack importer.
590
594
 
591
595
  This can improve performance in some cases, though use it with caution because aliases and `@import` at-rules starting with `~` will not work.
592
- You can pass your own `importer` to solve this (see [`importer docs`](https://github.com/sass/node-sass#importer--v200---experimental)).
596
+ You can pass your own `importer` to solve this (see [`importer` docs](https://github.com/sass/node-sass#importer--v200---experimental)).
593
597
 
594
598
  **webpack.config.js**
595
599
 
@@ -649,7 +653,7 @@ $known-prefixes: webkit, moz, ms, o;
649
653
  }
650
654
  ```
651
655
 
652
- The presented code will throw a webpack warning instead logging.
656
+ The presented code will throw a webpack warning instead of logging.
653
657
 
654
658
  To ignore unnecessary warnings you can use the [ignoreWarnings](https://webpack.js.org/configuration/other-options/#ignorewarnings) option.
655
659
 
@@ -691,11 +695,11 @@ Allows you to switch between the `legacy` and `modern` APIs. You can find more i
691
695
 
692
696
  > [!NOTE]
693
697
  >
694
- > 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.
698
+ > Using `modern-compiler` and `sass-embedded` together significantly improves performance and decreases build time. We strongly recommend their use. We will enable them by default in a future major release.
695
699
 
696
700
  > [!WARNING]
697
701
  >
698
- > The sass options are different for the `legacy` and `modern` APIs. Please look at [docs](https://sass-lang.com/documentation/js-api) how to migrate to the modern options.
702
+ > The Sass options are different for the `legacy` and `modern` APIs. Please look at [docs](https://sass-lang.com/documentation/js-api) to learn how to migrate to the modern options.
699
703
 
700
704
  **webpack.config.js**
701
705
 
@@ -726,7 +730,7 @@ module.exports = {
726
730
 
727
731
  ## How to enable `@debug` output
728
732
 
729
- By default, the output of `@debug` messages are disabled.
733
+ By default, the output of `@debug` messages is disabled.
730
734
  Add the following to **webpack.config.js** to enable them:
731
735
 
732
736
  ```js
@@ -742,11 +746,11 @@ module.exports = {
742
746
 
743
747
  ### Extracts CSS into separate files
744
748
 
745
- For production builds it's recommended to extract the CSS from your bundle to be able to use parallel loading of CSS/JS resources later on.
749
+ For production builds, it's recommended to extract the CSS from your bundle to enable parallel loading of CSS/JS resources.
746
750
 
747
751
  There are four recommended ways to extract a stylesheet from a bundle:
748
752
 
749
- #### 1. [mini-css-extract-plugin](https://github.com/webpack-contrib/mini-css-extract-plugin)
753
+ #### 1. [mini-css-extract-plugin](https://github.com/webpack/mini-css-extract-plugin)
750
754
 
751
755
  **webpack.config.js**
752
756
 
@@ -785,8 +789,10 @@ module.exports = {
785
789
  **webpack.config.js**
786
790
 
787
791
  ```js
792
+ const path = require("node:path");
793
+
788
794
  module.exports = {
789
- entry: [__dirname + "/src/scss/app.scss"],
795
+ entry: [path.resolve(__dirname, "./src/scss/app.scss")],
790
796
  module: {
791
797
  rules: [
792
798
  {
@@ -815,8 +821,10 @@ module.exports = {
815
821
  **webpack.config.js**
816
822
 
817
823
  ```js
824
+ const path = require("node:path");
825
+
818
826
  module.exports = {
819
- entry: [__dirname + "/src/scss/app.scss"],
827
+ entry: [path.resolve(__dirname, "./src/scss/app.scss")],
820
828
  module: {
821
829
  rules: [
822
830
  {
@@ -844,9 +852,9 @@ module.exports = {
844
852
 
845
853
  ### Source maps
846
854
 
847
- Enables/Disables generation of source maps.
855
+ Enables/disables generation of source maps.
848
856
 
849
- To enable CSS source maps, you'll need to pass the `sourceMap` option to the `sass-loader` _and_ the `css-loader`.
857
+ To enable CSS source maps, you'll need to pass the `sourceMap` option to both the `sass-loader` _and_ the `css-loader`.
850
858
 
851
859
  **webpack.config.js**
852
860
 
@@ -878,11 +886,13 @@ module.exports = {
878
886
  };
879
887
  ```
880
888
 
881
- If you want to edit the original Sass files inside Chrome, [there's a good blog post](https://medium.com/@toolmantim/getting-started-with-css-sourcemaps-and-in-browser-sass-editing-b4daab987fb0). Checkout [test/sourceMap](https://github.com/webpack-contrib/sass-loader/tree/master/test) for a running example.
889
+ If you want to edit the original Sass files inside Chrome, [there's a good blog post](https://medium.com/@toolmantim/getting-started-with-css-sourcemaps-and-in-browser-sass-editing-b4daab987fb0).
890
+ Checkout [test/sourceMap](https://github.com/webpack/sass-loader/tree/main/test) for a working example.
882
891
 
883
892
  ## Contributing
884
893
 
885
- Please take a moment to read our contributing guidelines if you haven't yet done so.
894
+ We welcome all contributions!
895
+ If you're new here, please take a moment to review our contributing guidelines before submitting issues or pull requests.
886
896
 
887
897
  [CONTRIBUTING](./.github/CONTRIBUTING.md)
888
898
 
@@ -894,11 +904,13 @@ Please take a moment to read our contributing guidelines if you haven't yet done
894
904
  [npm-url]: https://npmjs.com/package/sass-loader
895
905
  [node]: https://img.shields.io/node/v/sass-loader.svg
896
906
  [node-url]: https://nodejs.org
897
- [tests]: https://github.com/webpack-contrib/sass-loader/workflows/sass-loader/badge.svg
898
- [tests-url]: https://github.com/webpack-contrib/sass-loader/actions
899
- [cover]: https://codecov.io/gh/webpack-contrib/sass-loader/branch/master/graph/badge.svg
900
- [cover-url]: https://codecov.io/gh/webpack-contrib/sass-loader
907
+ [tests]: https://github.com/webpack/sass-loader/workflows/sass-loader/badge.svg
908
+ [tests-url]: https://github.com/webpack/sass-loader/actions
909
+ [cover]: https://codecov.io/gh/webpack/sass-loader/branch/main/graph/badge.svg
910
+ [cover-url]: https://codecov.io/gh/webpack/sass-loader
901
911
  [discussion]: https://img.shields.io/github/discussions/webpack/webpack
902
912
  [discussion-url]: https://github.com/webpack/webpack/discussions
903
913
  [size]: https://packagephobia.now.sh/badge?p=sass-loader
904
914
  [size-url]: https://packagephobia.now.sh/result?p=sass-loader
915
+ [discord-invite]: https://img.shields.io/discord/1180618526436888586?style=flat&logo=discord&logoColor=white&label=discord
916
+ [discord-url]: https://discord.gg/ARKBCXBu
package/dist/index.js CHANGED
@@ -4,16 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _url = _interopRequireDefault(require("url"));
8
- var _path = _interopRequireDefault(require("path"));
7
+ var _nodePath = _interopRequireDefault(require("node:path"));
8
+ var _nodeUrl = _interopRequireDefault(require("node:url"));
9
9
  var _options = _interopRequireDefault(require("./options.json"));
10
10
  var _utils = require("./utils");
11
11
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ // eslint-disable-next-line jsdoc/no-restricted-syntax
12
13
  /**
13
14
  * The sass-loader makes node-sass and dart-sass available to webpack modules.
14
- *
15
- * @this {object}
16
- * @param {string} content
15
+ * @this {LoaderContext<{ string: any }>}
16
+ * @param {string} content content
17
17
  */
18
18
  async function loader(content) {
19
19
  const options = this.getOptions(_options.default);
@@ -57,19 +57,19 @@ async function loader(content) {
57
57
  // There are situations when the `file`/`span.url` property do not exist
58
58
  // Modern API
59
59
  if (error.span && typeof error.span.url !== "undefined") {
60
- this.addDependency(_url.default.fileURLToPath(error.span.url));
60
+ this.addDependency(_nodeUrl.default.fileURLToPath(error.span.url));
61
61
  }
62
62
  // Legacy API
63
63
  else if (typeof error.file !== "undefined") {
64
64
  // `node-sass` returns POSIX paths
65
- this.addDependency(_path.default.normalize(error.file));
65
+ this.addDependency(_nodePath.default.normalize(error.file));
66
66
  }
67
67
  callback((0, _utils.errorFactory)(error));
68
68
  return;
69
69
  }
70
70
  let map =
71
71
  // Modern API, then legacy API
72
- result.sourceMap ? result.sourceMap : result.map ? JSON.parse(result.map) : null;
72
+ result.sourceMap || (result.map ? JSON.parse(result.map) : null);
73
73
 
74
74
  // Modify source paths only for webpack, otherwise we do nothing
75
75
  if (map && useSourceMap) {
@@ -78,25 +78,25 @@ async function loader(content) {
78
78
 
79
79
  // Modern API
80
80
  if (typeof result.loadedUrls !== "undefined") {
81
- result.loadedUrls.filter(loadedUrl => loadedUrl.protocol === "file:").forEach(includedFile => {
82
- const normalizedIncludedFile = _url.default.fileURLToPath(includedFile);
81
+ for (const includedFile of result.loadedUrls.filter(loadedUrl => loadedUrl.protocol === "file:")) {
82
+ const normalizedIncludedFile = _nodeUrl.default.fileURLToPath(includedFile);
83
83
 
84
84
  // Custom `importer` can return only `contents` so includedFile will be relative
85
- if (_path.default.isAbsolute(normalizedIncludedFile)) {
85
+ if (_nodePath.default.isAbsolute(normalizedIncludedFile)) {
86
86
  this.addDependency(normalizedIncludedFile);
87
87
  }
88
- });
88
+ }
89
89
  }
90
90
  // Legacy API
91
91
  else if (typeof result.stats !== "undefined" && typeof result.stats.includedFiles !== "undefined") {
92
- result.stats.includedFiles.forEach(includedFile => {
93
- const normalizedIncludedFile = _path.default.normalize(includedFile);
92
+ for (const includedFile of result.stats.includedFiles) {
93
+ const normalizedIncludedFile = _nodePath.default.normalize(includedFile);
94
94
 
95
95
  // Custom `importer` can return only `contents` so includedFile will be relative
96
- if (_path.default.isAbsolute(normalizedIncludedFile)) {
96
+ if (_nodePath.default.isAbsolute(normalizedIncludedFile)) {
97
97
  this.addDependency(normalizedIncludedFile);
98
98
  }
99
- });
99
+ }
100
100
  }
101
101
  callback(null, result.css.toString(), map);
102
102
  }
package/dist/options.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "properties": {
5
5
  "implementation": {
6
6
  "description": "The implementation of the sass to be used.",
7
- "link": "https://github.com/webpack-contrib/sass-loader#implementation",
7
+ "link": "https://github.com/webpack/sass-loader#implementation",
8
8
  "anyOf": [
9
9
  {
10
10
  "type": "string"
@@ -16,12 +16,12 @@
16
16
  },
17
17
  "api": {
18
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",
19
+ "link": "https://github.com/webpack/sass-loader#sassoptions",
20
20
  "enum": ["legacy", "modern", "modern-compiler"]
21
21
  },
22
22
  "sassOptions": {
23
23
  "description": "Options for `node-sass` or `sass` (`Dart Sass`) implementation.",
24
- "link": "https://github.com/webpack-contrib/sass-loader#sassoptions",
24
+ "link": "https://github.com/webpack/sass-loader#sassoptions",
25
25
  "anyOf": [
26
26
  {
27
27
  "type": "object",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "additionalData": {
36
36
  "description": "Prepends/Appends `Sass`/`SCSS` code before the actual entry file.",
37
- "link": "https://github.com/webpack-contrib/sass-loader#additionaldata",
37
+ "link": "https://github.com/webpack/sass-loader#additionaldata",
38
38
  "anyOf": [
39
39
  {
40
40
  "type": "string"
@@ -46,17 +46,17 @@
46
46
  },
47
47
  "sourceMap": {
48
48
  "description": "Enables/Disables generation of source maps.",
49
- "link": "https://github.com/webpack-contrib/sass-loader#sourcemap",
49
+ "link": "https://github.com/webpack/sass-loader#sourcemap",
50
50
  "type": "boolean"
51
51
  },
52
52
  "webpackImporter": {
53
53
  "description": "Enables/Disables default `webpack` importer.",
54
- "link": "https://github.com/webpack-contrib/sass-loader#webpackimporter",
54
+ "link": "https://github.com/webpack/sass-loader#webpackimporter",
55
55
  "type": "boolean"
56
56
  },
57
57
  "warnRuleAsWarning": {
58
58
  "description": "Treats the '@warn' rule as a webpack warning.",
59
- "link": "https://github.com/webpack-contrib/sass-loader#warnruleaswarning",
59
+ "link": "https://github.com/webpack/sass-loader#warnruleaswarning",
60
60
  "type": "boolean"
61
61
  }
62
62
  },
package/dist/utils.js CHANGED
@@ -11,33 +11,47 @@ exports.getSassOptions = getSassOptions;
11
11
  exports.getWebpackImporter = getWebpackImporter;
12
12
  exports.getWebpackResolver = getWebpackResolver;
13
13
  exports.normalizeSourceMap = normalizeSourceMap;
14
- var _url = _interopRequireDefault(require("url"));
15
- var _path = _interopRequireDefault(require("path"));
14
+ var _nodePath = _interopRequireDefault(require("node:path"));
15
+ var _nodeUrl = _interopRequireDefault(require("node:url"));
16
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
+ /** @typedef {import("sass")} Sass */
18
+ /** @typedef {import("sass").StringOptionsWithImporter} SassSassOptions */
19
+ /** @typedef {import("sass-embedded")} SassEmbedded */
20
+ /** @typedef {import("sass-embedded").StringOptionsWithImporter} SassEmbeddedOptions */
21
+
22
+ /** @typedef {Sass | SassEmbedded} SassImplementation */
23
+ /** @typedef {SassSassOptions | SassEmbeddedOptions} SassOptions */
24
+ // eslint-disable-next-line jsdoc/no-restricted-syntax
25
+ /** @typedef {Record<string, any>} LoaderOptions */
26
+
27
+ /**
28
+ * @returns {Sass | SassEmbedded} sass implementation
29
+ */
17
30
  function getDefaultSassImplementation() {
18
31
  let sassImplPkg = "sass";
19
32
  try {
20
33
  require.resolve("sass-embedded");
21
34
  sassImplPkg = "sass-embedded";
22
- } catch (ignoreError) {
35
+ } catch {
23
36
  try {
24
37
  require.resolve("sass");
25
- } catch (_ignoreError) {
38
+ } catch {
26
39
  try {
27
40
  require.resolve("node-sass");
28
41
  sassImplPkg = "node-sass";
29
- } catch (__ignoreError) {
42
+ } catch {
30
43
  sassImplPkg = "sass";
31
44
  }
32
45
  }
33
46
  }
34
-
35
- // eslint-disable-next-line import/no-dynamic-require, global-require
36
47
  return require(sassImplPkg);
37
48
  }
38
49
 
39
50
  /**
40
51
  * This function is not Webpack-specific and can be used by tools wishing to mimic `sass-loader`'s behaviour, so its signature should not be changed.
52
+ * @param {LoaderContext} loaderContext loader context
53
+ * @param {SassImplementation} implementation sass implementation
54
+ * @returns {SassImplementation} resolved sass implementation
41
55
  */
42
56
  function getSassImplementation(loaderContext, implementation) {
43
57
  let resolvedImplementation = implementation;
@@ -45,7 +59,6 @@ function getSassImplementation(loaderContext, implementation) {
45
59
  resolvedImplementation = getDefaultSassImplementation();
46
60
  }
47
61
  if (typeof resolvedImplementation === "string") {
48
- // eslint-disable-next-line import/no-dynamic-require, global-require
49
62
  resolvedImplementation = require(resolvedImplementation);
50
63
  }
51
64
  const {
@@ -60,27 +73,30 @@ function getSassImplementation(loaderContext, implementation) {
60
73
  }
61
74
  const [implementationName] = infoParts;
62
75
  if (implementationName === "dart-sass") {
63
- // eslint-disable-next-line consistent-return
64
76
  return resolvedImplementation;
65
77
  } else if (implementationName === "node-sass") {
66
- // eslint-disable-next-line consistent-return
67
78
  return resolvedImplementation;
68
79
  } else if (implementationName === "sass-embedded") {
69
- // eslint-disable-next-line consistent-return
70
80
  return resolvedImplementation;
71
81
  }
72
82
  throw new Error(`Unknown Sass implementation "${implementationName}".`);
73
83
  }
74
84
 
75
85
  /**
76
- * @param {any} loaderContext
77
- * @returns {boolean}
86
+ * @param {LoaderContext} loaderContext loader context
87
+ * @returns {boolean} true when mode is production, otherwise false
78
88
  */
79
89
  function isProductionLikeMode(loaderContext) {
80
90
  return loaderContext.mode === "production" || !loaderContext.mode;
81
91
  }
92
+
93
+ /**
94
+ * @param {Importer[]} importers importers
95
+ * @param {LoaderContext} loaderContext loader context
96
+ * @returns {Importer[]} proxied importers
97
+ */
82
98
  function proxyCustomImporters(importers, loaderContext) {
83
- return [].concat(importers).map(importer => function proxyImporter(...args) {
99
+ return [importers].flat().map(importer => function proxyImporter(...args) {
84
100
  const self = {
85
101
  ...this,
86
102
  webpackLoaderContext: loaderContext
@@ -91,14 +107,13 @@ function proxyCustomImporters(importers, loaderContext) {
91
107
 
92
108
  /**
93
109
  * Derives the sass options from the loader context and normalizes its values with sane defaults.
94
- *
95
- * @param {object} loaderContext
96
- * @param {object} loaderOptions
97
- * @param {string} content
98
- * @param {object} implementation
99
- * @param {boolean} useSourceMap
100
- * @param {"legacy" | "modern" | "modern-compiler"} apiType
101
- * @returns {Object}
110
+ * @param {LoaderContext} loaderContext loader context
111
+ * @param {LoaderOptions} loaderOptions loader options
112
+ * @param {string} content content
113
+ * @param {SassImplementation} implementation sass implementation
114
+ * @param {boolean} useSourceMap true when need to generate source maps, otherwise false
115
+ * @param {"legacy" | "modern" | "modern-compiler"} apiType api type
116
+ * @returns {SassOptions} sass options
102
117
  */
103
118
  async function getSassOptions(loaderContext, loaderOptions, content, implementation, useSourceMap, apiType) {
104
119
  const options = loaderOptions.sassOptions ? typeof loaderOptions.sassOptions === "function" ? loaderOptions.sassOptions(loaderContext) || {} : loaderOptions.sassOptions : {};
@@ -151,7 +166,7 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
151
166
  resourcePath
152
167
  } = loaderContext;
153
168
  if (isModernAPI) {
154
- sassOptions.url = _url.default.pathToFileURL(resourcePath);
169
+ sassOptions.url = _nodeUrl.default.pathToFileURL(resourcePath);
155
170
 
156
171
  // opt.outputStyle
157
172
  if (!sassOptions.style && isProductionLikeMode(loaderContext)) {
@@ -164,7 +179,7 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
164
179
 
165
180
  // If we are compiling sass and indentedSyntax isn't set, automatically set it.
166
181
  if (typeof sassOptions.syntax === "undefined") {
167
- const ext = _path.default.extname(resourcePath);
182
+ const ext = _nodePath.default.extname(resourcePath);
168
183
  if (ext && ext.toLowerCase() === ".scss") {
169
184
  sassOptions.syntax = "scss";
170
185
  } else if (ext && ext.toLowerCase() === ".sass") {
@@ -173,10 +188,10 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
173
188
  sassOptions.syntax = "css";
174
189
  }
175
190
  }
176
- sassOptions.loadPaths = [].concat(
191
+ sassOptions.loadPaths = [
177
192
  // We use `loadPaths` in context for resolver, so it should be always absolute
178
- (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" ? ";" : ":") : []);
179
- sassOptions.importers = sassOptions.importers ? Array.isArray(sassOptions.importers) ? sassOptions.importers.slice() : [sassOptions.importers] : [];
193
+ ...(sassOptions.loadPaths ? [...sassOptions.loadPaths] : []).map(includePath => _nodePath.default.isAbsolute(includePath) ? includePath : _nodePath.default.join(process.cwd(), includePath)), ...(process.env.SASS_PATH ? process.env.SASS_PATH.split(process.platform === "win32" ? ";" : ":") : [])];
194
+ sassOptions.importers = sassOptions.importers ? Array.isArray(sassOptions.importers) ? [...sassOptions.importers] : [sassOptions.importers] : [];
180
195
  } else {
181
196
  sassOptions.file = resourcePath;
182
197
 
@@ -192,12 +207,12 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
192
207
  // all paths in sourceMap.sources will be relative to that path.
193
208
  // Pretty complicated... :(
194
209
  sassOptions.sourceMap = true;
195
- sassOptions.outFile = _path.default.join(loaderContext.rootContext, "style.css.map");
210
+ sassOptions.outFile = _nodePath.default.join(loaderContext.rootContext, "style.css.map");
196
211
  sassOptions.sourceMapContents = true;
197
212
  sassOptions.omitSourceMapUrl = true;
198
213
  sassOptions.sourceMapEmbed = false;
199
214
  }
200
- const ext = _path.default.extname(resourcePath);
215
+ const ext = _nodePath.default.extname(resourcePath);
201
216
 
202
217
  // If we are compiling sass and indentedSyntax isn't set, automatically set it.
203
218
  if (ext && ext.toLowerCase() === ".sass" && typeof sassOptions.indentedSyntax === "undefined") {
@@ -207,16 +222,15 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
207
222
  }
208
223
 
209
224
  // Allow passing custom importers to `sass`/`node-sass`. Accepts `Function` or an array of `Function`s.
210
- sassOptions.importer = sassOptions.importer ? proxyCustomImporters(Array.isArray(sassOptions.importer) ? sassOptions.importer.slice() : [sassOptions.importer], loaderContext) : [];
225
+ sassOptions.importer = sassOptions.importer ? proxyCustomImporters(Array.isArray(sassOptions.importer) ? [...sassOptions.importer] : [sassOptions.importer], loaderContext) : [];
211
226
 
212
227
  // Regression on the `sass-embedded` side
213
228
  if (loaderOptions.webpackImporter === false && sassOptions.importer.length === 0) {
214
- // eslint-disable-next-line no-undefined
215
229
  sassOptions.importer = undefined;
216
230
  }
217
- sassOptions.includePaths = [].concat(process.cwd()).concat(
231
+ sassOptions.includePaths = [process.cwd(), ...
218
232
  // We use `includePaths` in context for resolver, so it should be always absolute
219
- (sassOptions.includePaths ? sassOptions.includePaths.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" ? ";" : ":") : []);
233
+ (sassOptions.includePaths ? [...sassOptions.includePaths] : []).map(includePath => _nodePath.default.isAbsolute(includePath) ? includePath : _nodePath.default.join(process.cwd(), includePath)), ...(process.env.SASS_PATH ? process.env.SASS_PATH.split(process.platform === "win32" ? ";" : ":") : [])];
220
234
  if (typeof sassOptions.charset === "undefined") {
221
235
  sassOptions.charset = true;
222
236
  }
@@ -243,15 +257,12 @@ const IS_PKG_SCHEME = /^pkg:/i;
243
257
  *
244
258
  * We don't need emulate `dart-sass` "It's not clear which file to import." errors (when "file.ext" and "_file.ext" files are present simultaneously in the same directory).
245
259
  * This reduces performance and `dart-sass` always do it on own side.
246
- *
247
- * @param {string} url
248
- * @param {boolean} forWebpackResolver
249
- * @param {boolean} fromImport
250
- * @returns {Array<string>}
260
+ * @param {string} url url
261
+ * @param {boolean} forWebpackResolver true when for webpack resolver, otherwise false
262
+ * @param {boolean} fromImport true when from `@import`, otherwise false
263
+ * @returns {string[]} possible requests
251
264
  */
252
- function getPossibleRequests(
253
- // eslint-disable-next-line no-shadow
254
- url, forWebpackResolver = false, fromImport = false) {
265
+ function getPossibleRequests(url, forWebpackResolver = false, fromImport = false) {
255
266
  let request = url;
256
267
 
257
268
  // In case there is module request, send this to webpack resolver
@@ -270,8 +281,8 @@ url, forWebpackResolver = false, fromImport = false) {
270
281
  }
271
282
 
272
283
  // Keep in mind: ext can also be something like '.datepicker' when the true extension is omitted and the filename contains a dot.
273
- // @see https://github.com/webpack-contrib/sass-loader/issues/167
274
- const extension = _path.default.extname(request).toLowerCase();
284
+ // @see https://github.com/webpack/sass/issues/167
285
+ const extension = _nodePath.default.extname(request).toLowerCase();
275
286
 
276
287
  // Because @import is also defined in CSS, Sass needs a way of compiling plain CSS @imports without trying to import the files at compile time.
277
288
  // To accomplish this, and to ensure SCSS is as much of a superset of CSS as possible, Sass will compile any @imports with the following characteristics to plain CSS imports:
@@ -281,15 +292,21 @@ url, forWebpackResolver = false, fromImport = false) {
281
292
  // - imports that have media queries.
282
293
  //
283
294
  // The `node-sass` package sends `@import` ending on `.css` to importer, it is bug, so we skip resolve
295
+ // Also sass outputs as is `@import "style.css"`, but `@use "style.css"` should include CSS content
284
296
  if (extension === ".css") {
285
- return [];
297
+ return fromImport ? [] : [url];
286
298
  }
287
- const dirname = _path.default.dirname(request);
299
+ const dirname = _nodePath.default.dirname(request);
288
300
  const normalizedDirname = dirname === "." ? "" : `${dirname}/`;
289
- const basename = _path.default.basename(request);
290
- const basenameWithoutExtension = _path.default.basename(request, extension);
291
- return [...new Set([].concat(fromImport ? [`${normalizedDirname}_${basenameWithoutExtension}.import${extension}`, `${normalizedDirname}${basenameWithoutExtension}.import${extension}`] : []).concat([`${normalizedDirname}_${basename}`, `${normalizedDirname}${basename}`]).concat(forWebpackResolver ? [url] : []))];
301
+ const basename = _nodePath.default.basename(request);
302
+ const basenameWithoutExtension = _nodePath.default.basename(request, extension);
303
+ return [...new Set([...[fromImport ? [`${normalizedDirname}_${basenameWithoutExtension}.import${extension}`, `${normalizedDirname}${basenameWithoutExtension}.import${extension}`] : []].flat(), `${normalizedDirname}_${basename}`, `${normalizedDirname}${basename}`, ...(forWebpackResolver ? [url] : [])])];
292
304
  }
305
+
306
+ /**
307
+ * @param {(context: string, request: string, callback: (error: Error | null, result: string) => void) => void} callbackResolve callback resolve
308
+ * @returns {(context: string, request: string) => Promise<string>} promise resolve
309
+ */
293
310
  function promiseResolve(callbackResolve) {
294
311
  return (context, request) => new Promise((resolve, reject) => {
295
312
  callbackResolve(context, request, (error, result) => {
@@ -301,15 +318,20 @@ function promiseResolve(callbackResolve) {
301
318
  });
302
319
  });
303
320
  }
321
+
322
+ /**
323
+ * @param {ResolutionMap} resolutionMap resolution map
324
+ * @returns {Promise<string>} resolved value
325
+ */
304
326
  async function startResolving(resolutionMap) {
305
327
  if (resolutionMap.length === 0) {
306
- return Promise.reject();
328
+ throw new Error("Next");
307
329
  }
308
330
  const [{
309
331
  possibleRequests
310
332
  }] = resolutionMap;
311
333
  if (possibleRequests.length === 0) {
312
- return Promise.reject();
334
+ throw new Error("Next");
313
335
  }
314
336
  const [{
315
337
  resolve,
@@ -317,14 +339,12 @@ async function startResolving(resolutionMap) {
317
339
  }] = resolutionMap;
318
340
  try {
319
341
  return await resolve(context, possibleRequests[0]);
320
- } catch (_ignoreError) {
342
+ } catch {
321
343
  const [, ...tailResult] = possibleRequests;
322
344
  if (tailResult.length === 0) {
323
345
  const [, ...tailResolutionMap] = resolutionMap;
324
346
  return startResolving(tailResolutionMap);
325
347
  }
326
-
327
- // eslint-disable-next-line no-param-reassign
328
348
  resolutionMap[0].possibleRequests = tailResult;
329
349
  return startResolving(resolutionMap);
330
350
  }
@@ -334,20 +354,15 @@ const IS_SPECIAL_MODULE_IMPORT = /^~[^/]+$/;
334
354
  const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
335
355
 
336
356
  /**
337
- * @public
338
357
  * Create the resolve function used in the custom Sass importer.
339
- *
340
358
  * Can be used by external tools to mimic how `sass-loader` works, for example
341
359
  * in a Jest transform. Such usages will want to wrap `resolve.create` from
342
360
  * [`enhanced-resolve`]{@link https://github.com/webpack/enhanced-resolve} to
343
361
  * pass as the `resolverFactory` argument.
344
- *
345
- * @param {Function} resolverFactory - A factory function for creating a Webpack
346
- * resolver.
347
- * @param {Object} implementation - The imported Sass implementation, both
348
- * `sass` (Dart Sass) and `node-sass` are supported.
349
- * @param {string[]} [includePaths] - The list of include paths passed to Sass.
350
- *
362
+ * @param {ResolveFactory} resolverFactory a factory function for creating a Webpack resolver.
363
+ * @param {Sass} implementation the imported Sass implementation, both `sass` (Dart Sass) and `node-sass` are supported.
364
+ * @param {string[]=} includePaths the list of include paths passed to Sass.
365
+ * @returns {Resolver} webpack resolver
351
366
  * @throws If a compatible Sass implementation cannot be found.
352
367
  */
353
368
  function getWebpackResolver(resolverFactory, implementation, includePaths = []) {
@@ -408,17 +423,15 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
408
423
  // See https://github.com/webpack/webpack/issues/12340
409
424
  // Because `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`
410
425
  // custom importer may not return `{ file: '/path/to/name.ext' }` and therefore our `context` will be relative
411
- if (!isModernSass && !_path.default.isAbsolute(context)) {
426
+ if (!isModernSass && !_nodePath.default.isAbsolute(context)) {
412
427
  return Promise.reject();
413
428
  }
414
429
  const originalRequest = request;
415
430
  const isFileScheme = originalRequest.slice(0, 5).toLowerCase() === "file:";
416
431
  if (isFileScheme) {
417
432
  try {
418
- // eslint-disable-next-line no-param-reassign
419
- request = _url.default.fileURLToPath(originalRequest);
420
- } catch (ignoreError) {
421
- // eslint-disable-next-line no-param-reassign
433
+ request = _nodeUrl.default.fileURLToPath(originalRequest);
434
+ } catch {
422
435
  request = request.slice(7);
423
436
  }
424
437
  }
@@ -447,32 +460,35 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
447
460
 
448
461
  // `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`, so we need emulate this too
449
462
  if (!isModernSass) {
450
- resolutionMap = resolutionMap.concat({
463
+ resolutionMap = [...resolutionMap, {
451
464
  resolve: fromImport ? sassImportResolve : sassModuleResolve,
452
- context: _path.default.dirname(context),
465
+ context: _nodePath.default.dirname(context),
453
466
  possibleRequests: sassPossibleRequests
454
- });
467
+ }];
455
468
  }
456
- resolutionMap = resolutionMap.concat(
457
- // eslint-disable-next-line no-shadow
458
- includePaths.map(context => {
459
- return {
460
- resolve: fromImport ? sassImportResolve : sassModuleResolve,
461
- context,
462
- possibleRequests: sassPossibleRequests
463
- };
464
- }));
469
+ resolutionMap = [...resolutionMap, ...includePaths.map(context => ({
470
+ resolve: fromImport ? sassImportResolve : sassModuleResolve,
471
+ context,
472
+ possibleRequests: sassPossibleRequests
473
+ }))];
465
474
  }
466
475
  const webpackPossibleRequests = getPossibleRequests(request, true, fromImport);
467
- resolutionMap = resolutionMap.concat({
476
+ resolutionMap = [...resolutionMap, {
468
477
  resolve: fromImport ? webpackImportResolve : webpackModuleResolve,
469
- context: _path.default.dirname(context),
478
+ context: _nodePath.default.dirname(context),
470
479
  possibleRequests: webpackPossibleRequests
471
- });
480
+ }];
472
481
  return startResolving(resolutionMap);
473
482
  };
474
483
  }
475
484
  const MATCH_CSS = /\.css$/i;
485
+
486
+ /**
487
+ * @param {LoaderContext} loaderContext loader context
488
+ * @param {SassImplementation} implementation sass implementation
489
+ * @param {string[]} loadPaths load paths
490
+ * @returns {Importer} the modern webpack importer
491
+ */
476
492
  function getModernWebpackImporter(loaderContext, implementation, loadPaths) {
477
493
  const resolve = getWebpackResolver(loaderContext.getResolve, implementation, loadPaths);
478
494
  return {
@@ -480,19 +496,19 @@ function getModernWebpackImporter(loaderContext, implementation, loadPaths) {
480
496
  const {
481
497
  fromImport
482
498
  } = context;
483
- const prev = context.containingUrl ? _url.default.fileURLToPath(context.containingUrl.toString()) : loaderContext.resourcePath;
499
+ const prev = context.containingUrl ? _nodeUrl.default.fileURLToPath(context.containingUrl.toString()) : loaderContext.resourcePath;
484
500
  let result;
485
501
  try {
486
502
  result = await resolve(prev, originalUrl, fromImport);
487
- } catch (err) {
503
+ } catch {
488
504
  // If no stylesheets are found, the importer should return null.
489
505
  return null;
490
506
  }
491
- loaderContext.addDependency(_path.default.normalize(result));
492
- return _url.default.pathToFileURL(result);
507
+ loaderContext.addDependency(_nodePath.default.normalize(result));
508
+ return _nodeUrl.default.pathToFileURL(result);
493
509
  },
494
510
  async load(canonicalUrl) {
495
- const ext = _path.default.extname(canonicalUrl.pathname);
511
+ const ext = _nodePath.default.extname(canonicalUrl.pathname);
496
512
  let syntax;
497
513
  if (ext && ext.toLowerCase() === ".scss") {
498
514
  syntax = "scss";
@@ -505,17 +521,16 @@ function getModernWebpackImporter(loaderContext, implementation, loadPaths) {
505
521
  syntax = "scss";
506
522
  }
507
523
  try {
508
- // eslint-disable-next-line no-shadow
509
524
  const contents = await new Promise((resolve, reject) => {
510
525
  // Old version of `enhanced-resolve` supports only path as a string
511
526
  // TODO simplify in the next major release and pass URL
512
- const canonicalPath = _url.default.fileURLToPath(canonicalUrl);
513
- loaderContext.fs.readFile(canonicalPath, "utf8", (err, content) => {
527
+ const canonicalPath = _nodeUrl.default.fileURLToPath(canonicalUrl);
528
+ loaderContext.fs.readFile(canonicalPath, (err, content) => {
514
529
  if (err) {
515
530
  reject(err);
516
531
  return;
517
532
  }
518
- resolve(content);
533
+ resolve(content.toString("utf8"));
519
534
  });
520
535
  });
521
536
  return {
@@ -523,23 +538,32 @@ function getModernWebpackImporter(loaderContext, implementation, loadPaths) {
523
538
  syntax,
524
539
  sourceMapUrl: canonicalUrl
525
540
  };
526
- } catch (err) {
541
+ } catch {
527
542
  return null;
528
543
  }
529
544
  }
530
545
  };
531
546
  }
547
+
548
+ /**
549
+ * @param {LoaderContext} loaderContext loader context
550
+ * @param {SassImplementation} implementation sass implementation
551
+ * @param {string[]} includePaths include paths
552
+ * @returns {Importer} the webpack importer
553
+ */
532
554
  function getWebpackImporter(loaderContext, implementation, includePaths) {
533
555
  const resolve = getWebpackResolver(loaderContext.getResolve, implementation, includePaths);
534
556
  return function importer(originalUrl, prev, done) {
535
557
  const {
536
558
  fromImport
537
559
  } = this;
538
- resolve(prev, originalUrl, fromImport).then(result => {
560
+ resolve(prev, originalUrl,
561
+ // For `node-sass`
562
+ typeof fromImport === "undefined" ? true : fromImport).then(result => {
539
563
  // Add the result as dependency.
540
564
  // Although we're also using stats.includedFiles, this might come in handy when an error occurs.
541
565
  // In this case, we don't get stats.includedFiles from node-sass/sass.
542
- loaderContext.addDependency(_path.default.normalize(result));
566
+ loaderContext.addDependency(_nodePath.default.normalize(result));
543
567
 
544
568
  // By removing the CSS file extension, we trigger node-sass to include the CSS file instead of just linking it.
545
569
  done({
@@ -559,11 +583,10 @@ const sassModernCompilers = new WeakMap();
559
583
 
560
584
  /**
561
585
  * Verifies that the implementation and version of Sass is supported by this loader.
562
- *
563
- * @param {Object} loaderContext
564
- * @param {Object} implementation
565
- * @param {"legacy" | "modern" | "modern-compiler"} apiType
566
- * @returns {Function}
586
+ * @param {LoaderContext} loaderContext loader context
587
+ * @param {SassImplementation} implementation sass implementation
588
+ * @param {"legacy" | "modern" | "modern-compiler"} apiType api type
589
+ * @returns {SassCompileFunction} compile function
567
590
  */
568
591
  function getCompileFn(loaderContext, implementation, apiType) {
569
592
  if (typeof implementation.compileStringAsync !== "undefined") {
@@ -578,7 +601,6 @@ function getCompileFn(loaderContext, implementation, apiType) {
578
601
  }
579
602
  if (apiType === "modern-compiler") {
580
603
  return async sassOptions => {
581
- // eslint-disable-next-line no-underscore-dangle
582
604
  const webpackCompiler = loaderContext._compiler;
583
605
  const {
584
606
  data,
@@ -628,8 +650,9 @@ function getCompileFn(loaderContext, implementation, apiType) {
628
650
  // We need to use a job queue to make sure that one thread is always available to the UV lib
629
651
  if (nodeSassJobQueue === null) {
630
652
  const threadPoolSize = Number(process.env.UV_THREADPOOL_SIZE || 4);
653
+
631
654
  // Only used for `node-sass`, so let's load it lazily
632
- // eslint-disable-next-line global-require
655
+
633
656
  const async = require("neo-async");
634
657
  nodeSassJobQueue = async.queue(implementation.render.bind(implementation), threadPoolSize - 1);
635
658
  }
@@ -646,8 +669,8 @@ function getCompileFn(loaderContext, implementation, apiType) {
646
669
  const ABSOLUTE_SCHEME = /^[A-Za-z0-9+\-.]+:/;
647
670
 
648
671
  /**
649
- * @param {string} source
650
- * @returns {"absolute" | "scheme-relative" | "path-absolute" | "path-absolute"}
672
+ * @param {string} source source
673
+ * @returns {"absolute" | "scheme-relative" | "path-absolute" | "path-absolute"} a type of URL
651
674
  */
652
675
  function getURLType(source) {
653
676
  if (source[0] === "/") {
@@ -661,44 +684,47 @@ function getURLType(source) {
661
684
  }
662
685
  return ABSOLUTE_SCHEME.test(source) ? "absolute" : "path-relative";
663
686
  }
687
+
688
+ /**
689
+ * @param {RawSourceMap} map source map
690
+ * @param {string} rootContext root context
691
+ * @returns {RawSourceMap} normalized source map
692
+ */
664
693
  function normalizeSourceMap(map, rootContext) {
665
694
  const newMap = map;
666
695
 
667
696
  // result.map.file is an optional property that provides the output filename.
668
697
  // Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it.
669
- // eslint-disable-next-line no-param-reassign
698
+
670
699
  if (typeof newMap.file !== "undefined") {
671
700
  delete newMap.file;
672
701
  }
673
-
674
- // eslint-disable-next-line no-param-reassign
675
702
  newMap.sourceRoot = "";
676
703
 
677
704
  // node-sass returns POSIX paths, that's why we need to transform them back to native paths.
678
705
  // This fixes an error on windows where the source-map module cannot resolve the source maps.
679
- // @see https://github.com/webpack-contrib/sass-loader/issues/366#issuecomment-279460722
680
- // eslint-disable-next-line no-param-reassign
706
+ // @see https://github.com/webpack/sass-loader/issues/366#issuecomment-279460722
707
+
681
708
  newMap.sources = newMap.sources.map(source => {
682
709
  const sourceType = getURLType(source);
683
710
 
684
711
  // Do no touch `scheme-relative`, `path-absolute` and `absolute` types (except `file:`)
685
712
  if (sourceType === "absolute" && /^file:/i.test(source)) {
686
- return _url.default.fileURLToPath(source);
713
+ return _nodeUrl.default.fileURLToPath(source);
687
714
  } else if (sourceType === "path-relative") {
688
- return _path.default.resolve(rootContext, _path.default.normalize(source));
715
+ return _nodePath.default.resolve(rootContext, _nodePath.default.normalize(source));
689
716
  }
690
717
  return source;
691
718
  });
692
719
  return newMap;
693
720
  }
721
+
722
+ /**
723
+ * @param {Error | SassError} error the original sass error
724
+ * @returns {Error} a new error
725
+ */
694
726
  function errorFactory(error) {
695
- let message;
696
- if (error.formatted) {
697
- message = error.formatted.replace(/^(.+)?Error: /, "");
698
- } else {
699
- // Keep original error if `sassError.formatted` is unavailable
700
- message = (error.message || error.toString()).replace(/^(.+)?Error: /, "");
701
- }
727
+ const message = error.formatted ? error.formatted.replace(/^(.+)?Error: /, "") : (error.message || error.toString()).replace(/^(.+)?Error: /, "");
702
728
  const obj = new Error(message, {
703
729
  cause: error
704
730
  });
package/package.json CHANGED
@@ -1,35 +1,41 @@
1
1
  {
2
2
  "name": "sass-loader",
3
- "version": "16.0.4",
3
+ "version": "16.0.6",
4
4
  "description": "Sass loader for webpack",
5
- "license": "MIT",
6
- "repository": "webpack-contrib/sass-loader",
7
- "author": "J. Tangelder",
8
- "homepage": "https://github.com/webpack-contrib/sass-loader",
9
- "bugs": "https://github.com/webpack-contrib/sass-loader/issues",
5
+ "keywords": [
6
+ "sass",
7
+ "libsass",
8
+ "webpack",
9
+ "loader"
10
+ ],
11
+ "homepage": "https://github.com/webpack/sass-loader",
12
+ "bugs": "https://github.com/webpack/sass-loader/issues",
13
+ "repository": "webpack/sass-loader",
10
14
  "funding": {
11
15
  "type": "opencollective",
12
16
  "url": "https://opencollective.com/webpack"
13
17
  },
18
+ "license": "MIT",
19
+ "author": "J. Tangelder",
14
20
  "main": "dist/cjs.js",
15
- "engines": {
16
- "node": ">= 18.12.0"
17
- },
21
+ "files": [
22
+ "dist"
23
+ ],
18
24
  "scripts": {
19
25
  "start": "npm run build -- -w",
20
26
  "clean": "del-cli dist",
21
27
  "prebuild": "npm run clean",
22
28
  "build": "cross-env NODE_ENV=production babel src -d dist --copy-files",
23
- "commitlint": "commitlint --from=master",
29
+ "commitlint": "commitlint --from=main",
24
30
  "security": "npm audit --production",
25
31
  "lint:prettier": "prettier --cache --list-different .",
26
- "lint:js": "eslint --cache .",
32
+ "lint:code": "eslint --cache .",
27
33
  "lint:spelling": "cspell --cache --no-must-find-files --quiet \"**/*.*\"",
28
34
  "lint": "npm-run-all -l -p \"lint:**\"",
29
35
  "test:only": "cross-env NODE_ENV=test jest",
30
- "fix:js": "npm run lint:js -- --fix",
36
+ "fix:code": "npm run lint:code -- --fix",
31
37
  "fix:prettier": "npm run lint:prettier -- --write",
32
- "fix": "npm-run-all -l fix:js fix:prettier",
38
+ "fix": "npm-run-all -l fix:code fix:prettier",
33
39
  "test:watch": "npm run test:only -- --watch",
34
40
  "test:manual": "npm run build && webpack-dev-server test/manual/src/index.js --open --config test/manual/webpack.config.js",
35
41
  "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
@@ -38,9 +44,59 @@
38
44
  "prepare": "husky && npm run build",
39
45
  "release": "standard-version"
40
46
  },
41
- "files": [
42
- "dist"
43
- ],
47
+ "dependencies": {
48
+ "neo-async": "^2.6.2"
49
+ },
50
+ "devDependencies": {
51
+ "@babel/cli": "^7.28.0",
52
+ "@babel/core": "^7.28.0",
53
+ "@babel/preset-env": "^7.28.0",
54
+ "@commitlint/cli": "^19.8.1",
55
+ "@commitlint/config-conventional": "^19.8.1",
56
+ "@eslint/js": "^9.32.0",
57
+ "@eslint/markdown": "^7.0.0",
58
+ "@stylistic/eslint-plugin": "^5.2.2",
59
+ "bootstrap-sass": "^3.4.1",
60
+ "bootstrap-v4": "npm:bootstrap@^4.5.3",
61
+ "bootstrap-v5": "npm:bootstrap@^5.3.7",
62
+ "cross-env": "^7.0.3",
63
+ "cspell": "^8.19.4",
64
+ "css-loader": "^6.9.0",
65
+ "del": "^6.1.1",
66
+ "del-cli": "^5.1.0",
67
+ "enhanced-resolve": "^5.18.2",
68
+ "eslint": "^9.32.0",
69
+ "eslint-config-prettier": "^10.1.8",
70
+ "eslint-config-webpack": "^4.5.1",
71
+ "eslint-plugin-import": "^2.32.0",
72
+ "eslint-plugin-jest": "^29.0.1",
73
+ "eslint-plugin-jsdoc": "^52.0.0",
74
+ "eslint-plugin-n": "^17.21.0",
75
+ "eslint-plugin-prettier": "^5.5.3",
76
+ "eslint-plugin-unicorn": "^60.0.0",
77
+ "file-loader": "^6.2.0",
78
+ "foundation-sites": "^6.7.5",
79
+ "globals": "^16.3.0",
80
+ "husky": "^9.1.3",
81
+ "jest": "^30.0.5",
82
+ "lint-staged": "^15.5.2",
83
+ "material-components-web": "^9.0.0",
84
+ "memfs": "^4.23.0",
85
+ "node-sass": "^9.0.0",
86
+ "node-sass-glob-importer": "^5.3.2",
87
+ "npm-run-all": "^4.1.5",
88
+ "prettier": "^3.6.2",
89
+ "sass": "^1.89.2",
90
+ "sass-embedded": "^1.89.2",
91
+ "semver": "^7.7.2",
92
+ "standard-version": "^9.3.1",
93
+ "style-loader": "^3.3.4",
94
+ "typescript": "^5.9.2",
95
+ "typescript-eslint": "^8.39.0",
96
+ "webpack": "^5.101.0",
97
+ "webpack-cli": "^6.0.1",
98
+ "webpack-dev-server": "^5.2.2"
99
+ },
44
100
  "peerDependencies": {
45
101
  "@rspack/core": "0.x || 1.x",
46
102
  "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
@@ -65,54 +121,7 @@
65
121
  "optional": true
66
122
  }
67
123
  },
68
- "dependencies": {
69
- "neo-async": "^2.6.2"
70
- },
71
- "devDependencies": {
72
- "@babel/cli": "^7.23.4",
73
- "@babel/core": "^7.24.0",
74
- "@babel/preset-env": "^7.24.0",
75
- "@commitlint/cli": "^19.3.0",
76
- "@commitlint/config-conventional": "^19.2.2",
77
- "@webpack-contrib/eslint-config-webpack": "^3.0.0",
78
- "babel-jest": "^29.6.2",
79
- "bootstrap-sass": "^3.4.1",
80
- "bootstrap-v4": "npm:bootstrap@^4.5.3",
81
- "bootstrap-v5": "npm:bootstrap@^5.0.1",
82
- "cross-env": "^7.0.3",
83
- "cspell": "^8.6.0",
84
- "css-loader": "^6.9.0",
85
- "del": "^6.1.1",
86
- "del-cli": "^5.1.0",
87
- "enhanced-resolve": "^5.15.1",
88
- "eslint": "^8.57.0",
89
- "eslint-config-prettier": "^9.1.0",
90
- "eslint-plugin-import": "^2.28.0",
91
- "file-loader": "^6.2.0",
92
- "foundation-sites": "^6.7.5",
93
- "husky": "^9.1.3",
94
- "jest": "^29.6.2",
95
- "jest-environment-node-single-context": "^29.1.0",
96
- "lint-staged": "^15.2.0",
97
- "material-components-web": "^9.0.0",
98
- "memfs": "^4.7.7",
99
- "node-sass": "^9.0.0",
100
- "node-sass-glob-importer": "^5.3.2",
101
- "npm-run-all": "^4.1.5",
102
- "prettier": "^3.2.2",
103
- "sass": "^1.71.1",
104
- "sass-embedded": "^1.71.1",
105
- "semver": "^7.5.4",
106
- "standard-version": "^9.3.1",
107
- "style-loader": "^3.3.4",
108
- "webpack": "^5.93.0",
109
- "webpack-cli": "^5.1.4",
110
- "webpack-dev-server": "^5.0.4"
111
- },
112
- "keywords": [
113
- "sass",
114
- "libsass",
115
- "webpack",
116
- "loader"
117
- ]
124
+ "engines": {
125
+ "node": ">= 18.12.0"
126
+ }
118
127
  }