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/dist/utils.js CHANGED
@@ -3,13 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.getCompileFn = getCompileFn;
7
+ exports.getModernWebpackImporter = getModernWebpackImporter;
6
8
  exports.getSassImplementation = getSassImplementation;
7
9
  exports.getSassOptions = getSassOptions;
8
- exports.getWebpackResolver = getWebpackResolver;
9
10
  exports.getWebpackImporter = getWebpackImporter;
10
- exports.getRenderFunctionFromSassImplementation = getRenderFunctionFromSassImplementation;
11
- exports.normalizeSourceMap = normalizeSourceMap;
11
+ exports.getWebpackResolver = getWebpackResolver;
12
12
  exports.isSupportedFibers = isSupportedFibers;
13
+ exports.normalizeSourceMap = normalizeSourceMap;
13
14
 
14
15
  var _url = _interopRequireDefault(require("url"));
15
16
 
@@ -19,6 +20,8 @@ var _full = require("klona/full");
19
20
 
20
21
  var _neoAsync = _interopRequireDefault(require("neo-async"));
21
22
 
23
+ var _SassWarning = _interopRequireDefault(require("./SassWarning"));
24
+
22
25
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
26
 
24
27
  function getDefaultSassImplementation() {
@@ -26,13 +29,19 @@ function getDefaultSassImplementation() {
26
29
 
27
30
  try {
28
31
  require.resolve("sass");
29
- } catch (error) {
32
+ } catch (ignoreError) {
30
33
  try {
31
34
  require.resolve("node-sass");
32
35
 
33
36
  sassImplPkg = "node-sass";
34
- } catch (ignoreError) {
35
- sassImplPkg = "sass";
37
+ } catch (_ignoreError) {
38
+ try {
39
+ require.resolve("sass-embedded");
40
+
41
+ sassImplPkg = "sass-embedded";
42
+ } catch (__ignoreError) {
43
+ sassImplPkg = "sass";
44
+ }
36
45
  }
37
46
  } // eslint-disable-next-line import/no-dynamic-require, global-require
38
47
 
@@ -91,6 +100,9 @@ function getSassImplementation(loaderContext, implementation) {
91
100
  } else if (implementationName === "node-sass") {
92
101
  // eslint-disable-next-line consistent-return
93
102
  return resolvedImplementation;
103
+ } else if (implementationName === "sass-embedded") {
104
+ // eslint-disable-next-line consistent-return
105
+ return resolvedImplementation;
94
106
  }
95
107
 
96
108
  loaderContext.emitError(new Error(`Unknown Sass implementation "${implementationName}".`));
@@ -133,72 +145,147 @@ function isSupportedFibers() {
133
145
  async function getSassOptions(loaderContext, loaderOptions, content, implementation, useSourceMap) {
134
146
  const options = (0, _full.klona)(loaderOptions.sassOptions ? typeof loaderOptions.sassOptions === "function" ? loaderOptions.sassOptions(loaderContext) || {} : loaderOptions.sassOptions : {});
135
147
  const isDartSass = implementation.info.includes("dart-sass");
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;
136
150
 
137
- if (isDartSass && isSupportedFibers()) {
138
- const shouldTryToResolveFibers = !options.fiber && options.fiber !== false;
151
+ if (!options.logger) {
152
+ // TODO set me to `true` by default in the next major release
153
+ const needEmitWarning = loaderOptions.warnRuleAsWarning === true;
154
+ const logger = loaderContext.getLogger("sass-loader");
139
155
 
140
- if (shouldTryToResolveFibers) {
141
- let fibers;
156
+ const formatSpan = span => `${span.url || "-"}:${span.start.line}:${span.start.column}: `;
142
157
 
143
- try {
144
- fibers = require.resolve("fibers");
145
- } catch (_error) {// Nothing
146
- }
158
+ options.logger = {
159
+ debug(message, loggerOptions) {
160
+ let builtMessage = "";
147
161
 
148
- if (fibers) {
149
- // eslint-disable-next-line global-require, import/no-dynamic-require
150
- options.fiber = require(fibers);
151
- }
152
- } else if (options.fiber === false) {
153
- // Don't pass the `fiber` option for `sass` (`Dart Sass`)
154
- delete options.fiber;
155
- }
156
- } else {
157
- // Don't pass the `fiber` option for `node-sass`
158
- delete options.fiber;
159
- }
162
+ if (loggerOptions.span) {
163
+ builtMessage = formatSpan(loggerOptions.span);
164
+ }
160
165
 
161
- options.file = loaderContext.resourcePath;
162
- options.data = loaderOptions.additionalData ? typeof loaderOptions.additionalData === "function" ? await loaderOptions.additionalData(content, loaderContext) : `${loaderOptions.additionalData}\n${content}` : content; // opt.outputStyle
166
+ builtMessage += message;
167
+ logger.debug(builtMessage);
168
+ },
163
169
 
164
- if (typeof options.outputStyle === "undefined" && isProductionLikeMode(loaderContext)) {
165
- options.outputStyle = "compressed";
166
- }
170
+ warn(message, loggerOptions) {
171
+ let builtMessage = "";
172
+
173
+ if (loggerOptions.deprecation) {
174
+ builtMessage += "Deprecation ";
175
+ }
176
+
177
+ if (loggerOptions.span && !loggerOptions.stack) {
178
+ builtMessage = formatSpan(loggerOptions.span);
179
+ }
180
+
181
+ builtMessage += message;
182
+
183
+ if (loggerOptions.stack) {
184
+ builtMessage += `\n\n${loggerOptions.stack}`;
185
+ }
186
+
187
+ if (needEmitWarning) {
188
+ loaderContext.emitWarning(new _SassWarning.default(builtMessage, loggerOptions));
189
+ } else {
190
+ logger.warn(builtMessage);
191
+ }
192
+ }
167
193
 
168
- if (useSourceMap) {
169
- // Deliberately overriding the sourceMap option here.
170
- // node-sass won't produce source maps if the data option is used and options.sourceMap is not a string.
171
- // In case it is a string, options.sourceMap should be a path where the source map is written.
172
- // But since we're using the data option, the source map will not actually be written, but
173
- // all paths in sourceMap.sources will be relative to that path.
174
- // Pretty complicated... :(
175
- options.sourceMap = true;
176
- options.outFile = _path.default.join(loaderContext.rootContext, "style.css.map");
177
- options.sourceMapContents = true;
178
- options.omitSourceMapUrl = true;
179
- options.sourceMapEmbed = false;
194
+ };
180
195
  }
181
196
 
182
197
  const {
183
198
  resourcePath
184
199
  } = loaderContext;
185
200
 
186
- const ext = _path.default.extname(resourcePath); // If we are compiling sass and indentedSyntax isn't set, automatically set it.
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
+
187
212
 
213
+ if (typeof options.syntax === "undefined") {
214
+ const ext = _path.default.extname(resourcePath);
188
215
 
189
- if (ext && ext.toLowerCase() === ".sass" && typeof options.indentedSyntax === "undefined") {
190
- options.indentedSyntax = true;
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) : [];
191
226
  } else {
192
- options.indentedSyntax = Boolean(options.indentedSyntax);
193
- } // Allow passing custom importers to `sass`/`node-sass`. Accepts `Function` or an array of `Function`s.
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
+
194
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.
195
280
 
196
- options.importer = options.importer ? proxyCustomImporters(Array.isArray(options.importer) ? options.importer : [options.importer], loaderContext) : [];
197
- options.includePaths = [].concat(process.cwd()).concat( // We use `includePaths` in context for resolver, so it should be always absolute
198
- (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" ? ";" : ":") : []);
199
281
 
200
- if (typeof options.charset === "undefined") {
201
- options.charset = true;
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
+ }
202
289
  }
203
290
 
204
291
  return options;
@@ -282,6 +369,40 @@ function promiseResolve(callbackResolve) {
282
369
  });
283
370
  }
284
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
+
285
406
  const IS_SPECIAL_MODULE_IMPORT = /^~[^/]+$/; // `[drive_letter]:\` + `\\[server]\[sharename]\`
286
407
 
287
408
  const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
@@ -304,41 +425,7 @@ const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
304
425
  */
305
426
 
306
427
  function getWebpackResolver(resolverFactory, implementation, includePaths = []) {
307
- async function startResolving(resolutionMap) {
308
- if (resolutionMap.length === 0) {
309
- return Promise.reject();
310
- }
311
-
312
- const [{
313
- possibleRequests
314
- }] = resolutionMap;
315
-
316
- if (possibleRequests.length === 0) {
317
- return Promise.reject();
318
- }
319
-
320
- const [{
321
- resolve,
322
- context
323
- }] = resolutionMap;
324
-
325
- try {
326
- return await resolve(context, possibleRequests[0]);
327
- } catch (_ignoreError) {
328
- const [, ...tailResult] = possibleRequests;
329
-
330
- if (tailResult.length === 0) {
331
- const [, ...tailResolutionMap] = resolutionMap;
332
- return startResolving(tailResolutionMap);
333
- } // eslint-disable-next-line no-param-reassign
334
-
335
-
336
- resolutionMap[0].possibleRequests = tailResult;
337
- return startResolving(resolutionMap);
338
- }
339
- }
340
-
341
- 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:
342
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`),
343
430
  // although `sass` look together by extensions (i.e. `_name.sass`/`name.sass`/`_name.scss`/`name.scss`/`_name.css`/`name.css`).
344
431
  // It shouldn't be a problem because `sass` throw errors:
@@ -462,6 +549,18 @@ function getWebpackResolver(resolverFactory, implementation, includePaths = [])
462
549
 
463
550
  const MATCH_CSS = /\.css$/i;
464
551
 
552
+ function getModernWebpackImporter() {
553
+ return {
554
+ async canonicalize() {
555
+ return null;
556
+ },
557
+
558
+ load() {// TODO implement
559
+ }
560
+
561
+ };
562
+ }
563
+
465
564
  function getWebpackImporter(loaderContext, implementation, includePaths) {
466
565
  const resolve = getWebpackResolver(loaderContext.getResolve, implementation, includePaths);
467
566
  return function importer(originalUrl, prev, done) {
@@ -491,14 +590,38 @@ let nodeSassJobQueue = null;
491
590
  * Verifies that the implementation and version of Sass is supported by this loader.
492
591
  *
493
592
  * @param {Object} implementation
593
+ * @param {Object} options
494
594
  * @returns {Function}
495
595
  */
496
596
 
497
- function getRenderFunctionFromSassImplementation(implementation) {
498
- 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
+ }
499
617
 
500
- if (isDartSass) {
501
- return implementation.render.bind(implementation);
618
+ resolve(result);
619
+ });
620
+ });
621
+ }
622
+
623
+ if (options.api === "modern") {
624
+ throw new Error("Modern API is not supported for 'node-sass'");
502
625
  } // There is an issue with node-sass when async custom importers are used
503
626
  // See https://github.com/sass/node-sass/issues/857#issuecomment-93594360
504
627
  // We need to use a job queue to make sure that one thread is always available to the UV lib
@@ -509,7 +632,16 @@ function getRenderFunctionFromSassImplementation(implementation) {
509
632
  nodeSassJobQueue = _neoAsync.default.queue(implementation.render.bind(implementation), threadPoolSize - 1);
510
633
  }
511
634
 
512
- 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
+ });
513
645
  }
514
646
 
515
647
  const ABSOLUTE_SCHEME = /^[A-Za-z0-9+\-.]+:/;
@@ -539,7 +671,10 @@ function normalizeSourceMap(map, rootContext) {
539
671
  // Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it.
540
672
  // eslint-disable-next-line no-param-reassign
541
673
 
542
- 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
+
543
678
 
544
679
  newMap.sourceRoot = ""; // node-sass returns POSIX paths, that's why we need to transform them back to native paths.
545
680
  // This fixes an error on windows where the source-map module cannot resolve the source maps.
@@ -547,9 +682,11 @@ function normalizeSourceMap(map, rootContext) {
547
682
  // eslint-disable-next-line no-param-reassign
548
683
 
549
684
  newMap.sources = newMap.sources.map(source => {
550
- 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:`)
551
686
 
552
- if (sourceType === "path-relative") {
687
+ if (sourceType === "absolute" && /^file:/i.test(source)) {
688
+ return _url.default.fileURLToPath(source);
689
+ } else if (sourceType === "path-relative") {
553
690
  return _path.default.resolve(rootContext, _path.default.normalize(source));
554
691
  }
555
692
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sass-loader",
3
- "version": "12.2.0",
3
+ "version": "12.6.0",
4
4
  "description": "Sass loader for webpack",
5
5
  "license": "MIT",
6
6
  "repository": "webpack-contrib/sass-loader",
@@ -39,8 +39,9 @@
39
39
  ],
40
40
  "peerDependencies": {
41
41
  "fibers": ">= 3.1.0",
42
- "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0",
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": "^13.1.0",
66
- "@commitlint/config-conventional": "^13.1.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": "^7.30.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": "^11.0.1",
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": "^6.0.1",
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",