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/dist/utils.js CHANGED
@@ -3,7 +3,8 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getRenderFunctionFromSassImplementation = getRenderFunctionFromSassImplementation;
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 (error) {
32
+ } catch (ignoreError) {
32
33
  try {
33
34
  require.resolve("node-sass");
34
35
 
35
36
  sassImplPkg = "node-sass";
36
- } catch (ignoreError) {
37
- sassImplPkg = "sass";
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,73 +145,8 @@ 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
- if (isDartSass && isSupportedFibers()) {
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
152
  // TODO set me to `true` by default in the next major release
@@ -249,6 +194,100 @@ async function getSassOptions(loaderContext, loaderOptions, content, implementat
249
194
  };
250
195
  }
251
196
 
197
+ const {
198
+ resourcePath
199
+ } = loaderContext;
200
+
201
+ if (isModernAPI) {
202
+ options.url = _url.default.pathToFileURL(resourcePath); // opt.outputStyle
203
+
204
+ if (!options.style && isProductionLikeMode(loaderContext)) {
205
+ options.style = "compressed";
206
+ }
207
+
208
+ if (useSourceMap) {
209
+ options.sourceMap = true;
210
+ } // If we are compiling sass and indentedSyntax isn't set, automatically set it.
211
+
212
+
213
+ if (typeof options.syntax === "undefined") {
214
+ const ext = _path.default.extname(resourcePath);
215
+
216
+ if (ext && ext.toLowerCase() === ".scss") {
217
+ options.syntax = "scss";
218
+ } else if (ext && ext.toLowerCase() === ".sass") {
219
+ options.syntax = "indented";
220
+ } else if (ext && ext.toLowerCase() === ".css") {
221
+ options.syntax = "css";
222
+ }
223
+ }
224
+
225
+ options.importers = options.importers ? proxyCustomImporters(Array.isArray(options.importers) ? options.importers : [options.importers], loaderContext) : [];
226
+ } else {
227
+ options.file = resourcePath;
228
+
229
+ if (isDartSass && isSupportedFibers()) {
230
+ const shouldTryToResolveFibers = !options.fiber && options.fiber !== false;
231
+
232
+ if (shouldTryToResolveFibers) {
233
+ let fibers;
234
+
235
+ try {
236
+ fibers = require.resolve("fibers");
237
+ } catch (_error) {// Nothing
238
+ }
239
+
240
+ if (fibers) {
241
+ // eslint-disable-next-line global-require, import/no-dynamic-require
242
+ options.fiber = require(fibers);
243
+ }
244
+ } else if (options.fiber === false) {
245
+ // Don't pass the `fiber` option for `sass` (`Dart Sass`)
246
+ delete options.fiber;
247
+ }
248
+ } else {
249
+ // Don't pass the `fiber` option for `node-sass`
250
+ delete options.fiber;
251
+ } // opt.outputStyle
252
+
253
+
254
+ if (!options.outputStyle && isProductionLikeMode(loaderContext)) {
255
+ options.outputStyle = "compressed";
256
+ }
257
+
258
+ if (useSourceMap) {
259
+ // Deliberately overriding the sourceMap option here.
260
+ // node-sass won't produce source maps if the data option is used and options.sourceMap is not a string.
261
+ // In case it is a string, options.sourceMap should be a path where the source map is written.
262
+ // But since we're using the data option, the source map will not actually be written, but
263
+ // all paths in sourceMap.sources will be relative to that path.
264
+ // Pretty complicated... :(
265
+ options.sourceMap = true;
266
+ options.outFile = _path.default.join(loaderContext.rootContext, "style.css.map");
267
+ options.sourceMapContents = true;
268
+ options.omitSourceMapUrl = true;
269
+ options.sourceMapEmbed = false;
270
+ }
271
+
272
+ const ext = _path.default.extname(resourcePath); // If we are compiling sass and indentedSyntax isn't set, automatically set it.
273
+
274
+
275
+ if (ext && ext.toLowerCase() === ".sass" && typeof options.indentedSyntax === "undefined") {
276
+ options.indentedSyntax = true;
277
+ } else {
278
+ options.indentedSyntax = Boolean(options.indentedSyntax);
279
+ } // Allow passing custom importers to `sass`/`node-sass`. Accepts `Function` or an array of `Function`s.
280
+
281
+
282
+ options.importer = options.importer ? proxyCustomImporters(Array.isArray(options.importer) ? options.importer : [options.importer], loaderContext) : [];
283
+ options.includePaths = [].concat(process.cwd()).concat( // We use `includePaths` in context for resolver, so it should be always absolute
284
+ (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" ? ";" : ":") : []);
285
+
286
+ if (typeof options.charset === "undefined") {
287
+ options.charset = true;
288
+ }
289
+ }
290
+
252
291
  return options;
253
292
  }
254
293
 
@@ -330,6 +369,40 @@ function promiseResolve(callbackResolve) {
330
369
  });
331
370
  }
332
371
 
372
+ async function startResolving(resolutionMap) {
373
+ if (resolutionMap.length === 0) {
374
+ return Promise.reject();
375
+ }
376
+
377
+ const [{
378
+ possibleRequests
379
+ }] = resolutionMap;
380
+
381
+ if (possibleRequests.length === 0) {
382
+ return Promise.reject();
383
+ }
384
+
385
+ const [{
386
+ resolve,
387
+ context
388
+ }] = resolutionMap;
389
+
390
+ try {
391
+ return await resolve(context, possibleRequests[0]);
392
+ } catch (_ignoreError) {
393
+ const [, ...tailResult] = possibleRequests;
394
+
395
+ if (tailResult.length === 0) {
396
+ const [, ...tailResolutionMap] = resolutionMap;
397
+ return startResolving(tailResolutionMap);
398
+ } // eslint-disable-next-line no-param-reassign
399
+
400
+
401
+ resolutionMap[0].possibleRequests = tailResult;
402
+ return startResolving(resolutionMap);
403
+ }
404
+ }
405
+
333
406
  const IS_SPECIAL_MODULE_IMPORT = /^~[^/]+$/; // `[drive_letter]:\` + `\\[server]\[sharename]\`
334
407
 
335
408
  const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
@@ -352,41 +425,7 @@ const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
352
425
  */
353
426
 
354
427
  function getWebpackResolver(resolverFactory, implementation, includePaths = []) {
355
- async function startResolving(resolutionMap) {
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:
428
+ 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
429
  // 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
430
  // although `sass` look together by extensions (i.e. `_name.sass`/`name.sass`/`_name.scss`/`name.scss`/`_name.css`/`name.css`).
392
431
  // It shouldn't be a problem because `sass` throw errors:
@@ -510,6 +549,18 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
510
549
 
511
550
  const MATCH_CSS = /\.css$/i;
512
551
 
552
+ function getModernWebpackImporter() {
553
+ return {
554
+ async canonicalize() {
555
+ return null;
556
+ },
557
+
558
+ load() {// TODO implement
559
+ }
560
+
561
+ };
562
+ }
563
+
513
564
  function getWebpackImporter(loaderContext, implementation, includePaths) {
514
565
  const resolve = getWebpackResolver(loaderContext.getResolve, implementation, includePaths);
515
566
  return function importer(originalUrl, prev, done) {
@@ -539,14 +590,38 @@ let nodeSassJobQueue = null;
539
590
  * Verifies that the implementation and version of Sass is supported by this loader.
540
591
  *
541
592
  * @param {Object} implementation
593
+ * @param {Object} options
542
594
  * @returns {Function}
543
595
  */
544
596
 
545
- function getRenderFunctionFromSassImplementation(implementation) {
546
- const isDartSass = implementation.info.includes("dart-sass");
597
+ function getCompileFn(implementation, options) {
598
+ const isNewSass = implementation.info.includes("dart-sass") || implementation.info.includes("sass-embedded");
599
+
600
+ if (isNewSass) {
601
+ if (options.api === "modern") {
602
+ return sassOptions => {
603
+ const {
604
+ data,
605
+ ...rest
606
+ } = sassOptions;
607
+ return implementation.compileStringAsync(data, rest);
608
+ };
609
+ }
610
+
611
+ return sassOptions => new Promise((resolve, reject) => {
612
+ implementation.render(sassOptions, (error, result) => {
613
+ if (error) {
614
+ reject(error);
615
+ return;
616
+ }
617
+
618
+ resolve(result);
619
+ });
620
+ });
621
+ }
547
622
 
548
- if (isDartSass) {
549
- return implementation.render.bind(implementation);
623
+ if (options.api === "modern") {
624
+ throw new Error("Modern API is not supported for 'node-sass'");
550
625
  } // There is an issue with node-sass when async custom importers are used
551
626
  // See https://github.com/sass/node-sass/issues/857#issuecomment-93594360
552
627
  // We need to use a job queue to make sure that one thread is always available to the UV lib
@@ -557,7 +632,16 @@ function getRenderFunctionFromSassImplementation(implementation) {
557
632
  nodeSassJobQueue = _neoAsync.default.queue(implementation.render.bind(implementation), threadPoolSize - 1);
558
633
  }
559
634
 
560
- return nodeSassJobQueue.push.bind(nodeSassJobQueue);
635
+ return sassOptions => new Promise((resolve, reject) => {
636
+ nodeSassJobQueue.push.bind(nodeSassJobQueue)(sassOptions, (error, result) => {
637
+ if (error) {
638
+ reject(error);
639
+ return;
640
+ }
641
+
642
+ resolve(result);
643
+ });
644
+ });
561
645
  }
562
646
 
563
647
  const ABSOLUTE_SCHEME = /^[A-Za-z0-9+\-.]+:/;
@@ -587,7 +671,10 @@ function normalizeSourceMap(map, rootContext) {
587
671
  // Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it.
588
672
  // eslint-disable-next-line no-param-reassign
589
673
 
590
- delete newMap.file; // eslint-disable-next-line no-param-reassign
674
+ if (typeof newMap.file !== "undefined") {
675
+ delete newMap.file;
676
+ } // eslint-disable-next-line no-param-reassign
677
+
591
678
 
592
679
  newMap.sourceRoot = ""; // node-sass returns POSIX paths, that's why we need to transform them back to native paths.
593
680
  // This fixes an error on windows where the source-map module cannot resolve the source maps.
@@ -595,9 +682,11 @@ function normalizeSourceMap(map, rootContext) {
595
682
  // eslint-disable-next-line no-param-reassign
596
683
 
597
684
  newMap.sources = newMap.sources.map(source => {
598
- const sourceType = getURLType(source); // Do no touch `scheme-relative`, `path-absolute` and `absolute` types
685
+ const sourceType = getURLType(source); // Do no touch `scheme-relative`, `path-absolute` and `absolute` types (except `file:`)
599
686
 
600
- if (sourceType === "path-relative") {
687
+ if (sourceType === "absolute" && /^file:/i.test(source)) {
688
+ return _url.default.fileURLToPath(source);
689
+ } else if (sourceType === "path-relative") {
601
690
  return _path.default.resolve(rootContext, _path.default.normalize(source));
602
691
  }
603
692
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sass-loader",
3
- "version": "12.4.0",
3
+ "version": "12.6.0",
4
4
  "description": "Sass loader for webpack",
5
5
  "license": "MIT",
6
6
  "repository": "webpack-contrib/sass-loader",
@@ -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.14.5",
63
- "@babel/core": "^7.14.6",
64
- "@babel/preset-env": "^7.14.7",
65
- "@commitlint/cli": "^15.0.0",
66
- "@commitlint/config-conventional": "^15.0.0",
66
+ "@babel/cli": "^7.17.0",
67
+ "@babel/core": "^7.17.0",
68
+ "@babel/preset-env": "^7.16.11",
69
+ "@commitlint/cli": "^16.2.1",
70
+ "@commitlint/config-conventional": "^16.2.1",
67
71
  "@webpack-contrib/eslint-config-webpack": "^3.0.0",
68
- "babel-jest": "^27.0.6",
72
+ "babel-jest": "^27.5.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.2.0",
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.1.0",
81
+ "eslint": "^8.8.0",
78
82
  "eslint-config-prettier": "^8.3.0",
79
- "eslint-plugin-import": "^2.23.3",
80
- "fibers": "^5.0.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
87
  "husky": "^7.0.1",
84
- "jest": "^27.0.6",
85
- "lint-staged": "^12.1.2",
88
+ "jest": "^27.5.0",
89
+ "jest-environment-node-single-context": "^27.2.0",
90
+ "lint-staged": "^12.3.3",
86
91
  "material-components-web": "^8.0.0",
87
- "memfs": "^3.2.2",
88
- "node-sass": "^7.0.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.35.2",
97
+ "sass": "^1.49.7",
98
+ "sass-embedded": "^1.49.7",
93
99
  "semver": "^7.3.5",
94
100
  "standard-version": "^9.3.1",
95
101
  "style-loader": "^3.2.1",
96
- "webpack": "^5.45.1"
102
+ "webpack": "^5.68.0"
97
103
  },
98
104
  "keywords": [
99
105
  "sass",