sass-loader 9.0.3 → 10.0.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [10.0.2](https://github.com/webpack-contrib/sass-loader/compare/v10.0.1...v10.0.2) (2020-09-03)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * source maps generation ([#886](https://github.com/webpack-contrib/sass-loader/issues/886)) ([8327d55](https://github.com/webpack-contrib/sass-loader/commit/8327d55df9e8fc6e24d2759d7bd50174ed1ff1e4))
11
+
12
+ ### [10.0.1](https://github.com/webpack-contrib/sass-loader/compare/v10.0.0...v10.0.1) (2020-08-25)
13
+
14
+ ### Chore
15
+
16
+ * update deps
17
+
18
+ ## [10.0.0](https://github.com/webpack-contrib/sass-loader/compare/v10.0.0-rc.0...v10.0.0) (2020-08-24)
19
+
20
+ ### Bug Fixes
21
+
22
+ * handle absolute windows path in source maps
23
+
24
+ ## [10.0.0-rc.0](https://github.com/webpack-contrib/sass-loader/compare/v9.0.3...v10.0.0-rc.0) (2020-08-24)
25
+
26
+
27
+ ### ⚠ BREAKING CHANGES
28
+
29
+ * loader generates absolute `sources` in source maps, also avoids modifying `sass` source maps if the `sourceMap` option is `false`
30
+
5
31
  ### [9.0.3](https://github.com/webpack-contrib/sass-loader/compare/v9.0.2...v9.0.3) (2020-08-05)
6
32
 
7
33
 
package/dist/index.js CHANGED
@@ -32,7 +32,8 @@ function loader(content) {
32
32
  baseDataPath: 'options'
33
33
  });
34
34
  const implementation = (0, _utils.getSassImplementation)(options.implementation);
35
- const sassOptions = (0, _utils.getSassOptions)(this, options, content, implementation);
35
+ const useSourceMap = typeof options.sourceMap === 'boolean' ? options.sourceMap : this.sourceMap;
36
+ const sassOptions = (0, _utils.getSassOptions)(this, options, content, implementation, useSourceMap);
36
37
  const shouldUseWebpackImporter = typeof options.webpackImporter === 'boolean' ? options.webpackImporter : true;
37
38
 
38
39
  if (shouldUseWebpackImporter) {
@@ -56,26 +57,16 @@ function loader(content) {
56
57
  return;
57
58
  }
58
59
 
59
- if (result.map) {
60
- // eslint-disable-next-line no-param-reassign
61
- result.map = JSON.parse(result.map); // result.map.file is an optional property that provides the output filename.
62
- // Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it.
63
- // eslint-disable-next-line no-param-reassign
60
+ let map = result.map ? JSON.parse(result.map) : null; // Modify source paths only for webpack, otherwise we do nothing
64
61
 
65
- delete result.map.file; // node-sass returns POSIX paths, that's why we need to transform them back to native paths.
66
- // This fixes an error on windows where the source-map module cannot resolve the source maps.
67
- // @see https://github.com/webpack-contrib/sass-loader/issues/366#issuecomment-279460722
68
- // eslint-disable-next-line no-param-reassign
69
-
70
- result.map.sourceRoot = _path.default.normalize(result.map.sourceRoot); // eslint-disable-next-line no-param-reassign
71
-
72
- result.map.sources = result.map.sources.map(_path.default.normalize);
62
+ if (map && useSourceMap) {
63
+ map = (0, _utils.normalizeSourceMap)(map, this.rootContext);
73
64
  }
74
65
 
75
66
  result.stats.includedFiles.forEach(includedFile => {
76
67
  this.addDependency(_path.default.normalize(includedFile));
77
68
  });
78
- callback(null, result.css.toString(), result.map);
69
+ callback(null, result.css.toString(), map);
79
70
  });
80
71
  }
81
72
 
package/dist/utils.js CHANGED
@@ -3,11 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.default = getPossibleRequests;
7
6
  exports.getSassImplementation = getSassImplementation;
8
7
  exports.getSassOptions = getSassOptions;
8
+ exports.getWebpackResolver = getWebpackResolver;
9
9
  exports.getWebpackImporter = getWebpackImporter;
10
10
  exports.getRenderFunctionFromSassImplementation = getRenderFunctionFromSassImplementation;
11
+ exports.normalizeSourceMap = normalizeSourceMap;
11
12
 
12
13
  var _url = _interopRequireDefault(require("url"));
13
14
 
@@ -15,7 +16,7 @@ var _path = _interopRequireDefault(require("path"));
15
16
 
16
17
  var _semver = _interopRequireDefault(require("semver"));
17
18
 
18
- var _klona = _interopRequireDefault(require("klona"));
19
+ var _full = require("klona/full");
19
20
 
20
21
  var _loaderUtils = require("loader-utils");
21
22
 
@@ -41,6 +42,12 @@ function getDefaultSassImplementation() {
41
42
 
42
43
  return require(sassImplPkg);
43
44
  }
45
+ /**
46
+ * @public
47
+ * This function is not Webpack-specific and can be used by tools wishing to
48
+ * mimic `sass-loader`'s behaviour, so its signature should not be changed.
49
+ */
50
+
44
51
 
45
52
  function getSassImplementation(implementation) {
46
53
  let resolvedImplementation = implementation;
@@ -102,12 +109,13 @@ function proxyCustomImporters(importers, loaderContext) {
102
109
  * @param {object} loaderOptions
103
110
  * @param {string} content
104
111
  * @param {object} implementation
112
+ * @param {boolean} useSourceMap
105
113
  * @returns {Object}
106
114
  */
107
115
 
108
116
 
109
- function getSassOptions(loaderContext, loaderOptions, content, implementation) {
110
- const options = (0, _klona.default)(loaderOptions.sassOptions ? typeof loaderOptions.sassOptions === 'function' ? loaderOptions.sassOptions(loaderContext) || {} : loaderOptions.sassOptions : {});
117
+ function getSassOptions(loaderContext, loaderOptions, content, implementation, useSourceMap) {
118
+ const options = (0, _full.klona)(loaderOptions.sassOptions ? typeof loaderOptions.sassOptions === 'function' ? loaderOptions.sassOptions(loaderContext) || {} : loaderOptions.sassOptions : {});
111
119
  const isDartSass = implementation.info.includes('dart-sass');
112
120
 
113
121
  if (isDartSass) {
@@ -141,8 +149,6 @@ function getSassOptions(loaderContext, loaderOptions, content, implementation) {
141
149
  options.outputStyle = 'compressed';
142
150
  }
143
151
 
144
- const useSourceMap = typeof loaderOptions.sourceMap === 'boolean' ? loaderOptions.sourceMap : loaderContext.sourceMap;
145
-
146
152
  if (useSourceMap) {
147
153
  // Deliberately overriding the sourceMap option here.
148
154
  // node-sass won't produce source maps if the data option is used and options.sourceMap is not a string.
@@ -150,8 +156,8 @@ function getSassOptions(loaderContext, loaderOptions, content, implementation) {
150
156
  // But since we're using the data option, the source map will not actually be written, but
151
157
  // all paths in sourceMap.sources will be relative to that path.
152
158
  // Pretty complicated... :(
153
- options.sourceMap = _path.default.join(process.cwd(), '/sass.css.map');
154
- options.sourceMapRoot = process.cwd();
159
+ options.sourceMap = true;
160
+ options.outFile = _path.default.join(loaderContext.rootContext, 'style.css.map');
155
161
  options.sourceMapContents = true;
156
162
  options.omitSourceMapUrl = true;
157
163
  options.sourceMapEmbed = false;
@@ -195,15 +201,14 @@ const isModuleImport = /^~([^/]+|[^/]+\/|@[^/]+[/][^/]+|@[^/]+\/?|@[^/]+[/][^/]+
195
201
  *
196
202
  * @param {string} url
197
203
  * @param {boolean} forWebpackResolver
198
- * @param {Object} loaderContext
204
+ * @param {string} rootContext
199
205
  * @returns {Array<string>}
200
206
  */
201
207
 
202
- function getPossibleRequests(loaderContext, // eslint-disable-next-line no-shadow
203
- url, forWebpackResolver = false) {
208
+ function getPossibleRequests( // eslint-disable-next-line no-shadow
209
+ url, forWebpackResolver = false, rootContext = false) {
204
210
  const request = (0, _loaderUtils.urlToRequest)(url, // Maybe it is server-relative URLs
205
- forWebpackResolver && url.charAt(0) === '/' ? loaderContext.rootContext : // eslint-disable-next-line no-undefined
206
- undefined); // In case there is module request, send this to webpack resolver
211
+ forWebpackResolver && rootContext); // In case there is module request, send this to webpack resolver
207
212
 
208
213
  if (forWebpackResolver && isModuleImport.test(url)) {
209
214
  return [...new Set([request, url])];
@@ -232,12 +237,41 @@ url, forWebpackResolver = false) {
232
237
  return [...new Set([`${dirname}/_${basename}`, request].concat(forWebpackResolver ? [`${_path.default.dirname(url)}/_${basename}`, url] : []))];
233
238
  }
234
239
 
235
- const matchCss = /\.css$/i;
236
- const isSpecialModuleImport = /^~[^/]+$/; // `[drive_letter]:\` + `\\[server]\[sharename]\`
240
+ function promiseResolve(callbackResolve) {
241
+ return (context, request) => new Promise((resolve, reject) => {
242
+ callbackResolve(context, request, (error, result) => {
243
+ if (error) {
244
+ reject(error);
245
+ } else {
246
+ resolve(result);
247
+ }
248
+ });
249
+ });
250
+ }
237
251
 
238
- const isNativeWin32Path = /^[a-zA-Z]:[/\\]|^\\\\/i;
252
+ const IS_SPECIAL_MODULE_IMPORT = /^~[^/]+$/; // `[drive_letter]:\` + `\\[server]\[sharename]\`
239
253
 
240
- function getWebpackImporter(loaderContext, implementation, includePaths) {
254
+ const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
255
+ /**
256
+ * @public
257
+ * Create the resolve function used in the custom Sass importer.
258
+ *
259
+ * Can be used by external tools to mimic how `sass-loader` works, for example
260
+ * in a Jest transform. Such usages will want to wrap `resolve.create` from
261
+ * [`enhanced-resolve`]{@link https://github.com/webpack/enhanced-resolve} to
262
+ * pass as the `resolverFactory` argument.
263
+ *
264
+ * @param {Function} resolverFactory - A factory function for creating a Webpack
265
+ * resolver.
266
+ * @param {Object} implementation - The imported Sass implementation, both
267
+ * `sass` (Dart Sass) and `node-sass` are supported.
268
+ * @param {string[]} [includePaths] - The list of include paths passed to Sass.
269
+ * @param {boolean} [rootContext] - The configured Webpack root context.
270
+ *
271
+ * @throws If a compatible Sass implementation cannot be found.
272
+ */
273
+
274
+ function getWebpackResolver(resolverFactory, implementation, includePaths = [], rootContext = false) {
241
275
  async function startResolving(resolutionMap) {
242
276
  if (resolutionMap.length === 0) {
243
277
  return Promise.reject();
@@ -248,10 +282,9 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
248
282
  context,
249
283
  possibleRequests
250
284
  }] = resolutionMap;
251
- let result;
252
285
 
253
286
  try {
254
- result = await resolve(context, possibleRequests[0]);
287
+ return await resolve(context, possibleRequests[0]);
255
288
  } catch (_ignoreError) {
256
289
  const [, ...tailResult] = possibleRequests;
257
290
 
@@ -263,19 +296,11 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
263
296
 
264
297
  resolutionMap[0].possibleRequests = tailResult;
265
298
  return startResolving(resolutionMap);
266
- } // Add the result as dependency.
267
- // Although we're also using stats.includedFiles, this might come in handy when an error occurs.
268
- // In this case, we don't get stats.includedFiles from node-sass/sass.
269
-
270
-
271
- loaderContext.addDependency(_path.default.normalize(result)); // By removing the CSS file extension, we trigger node-sass to include the CSS file instead of just linking it.
272
-
273
- return {
274
- file: result.replace(matchCss, '')
275
- };
299
+ }
276
300
  }
277
301
 
278
- const sassResolve = loaderContext.getResolve({
302
+ const isDartSass = implementation.info.includes('dart-sass');
303
+ const sassResolve = promiseResolve(resolverFactory({
279
304
  alias: [],
280
305
  aliasFields: [],
281
306
  conditionNames: [],
@@ -286,34 +311,35 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
286
311
  mainFiles: ['_index', 'index'],
287
312
  modules: [],
288
313
  restrictions: [/\.((sa|sc|c)ss)$/i]
289
- });
290
- const webpackResolve = loaderContext.getResolve({
314
+ }));
315
+ const webpackResolve = promiseResolve(resolverFactory({
291
316
  conditionNames: ['sass', 'style'],
292
317
  mainFields: ['sass', 'style', 'main', '...'],
293
318
  mainFiles: ['_index', 'index', '...'],
294
319
  extensions: ['.sass', '.scss', '.css'],
295
320
  restrictions: [/\.((sa|sc|c)ss)$/i]
296
- });
297
- return (originalUrl, prev, done) => {
298
- let request = originalUrl;
299
- const isFileScheme = originalUrl.slice(0, 5).toLowerCase() === 'file:';
321
+ }));
322
+ return (context, request) => {
323
+ const originalRequest = request;
324
+ const isFileScheme = originalRequest.slice(0, 5).toLowerCase() === 'file:';
300
325
 
301
326
  if (isFileScheme) {
302
327
  try {
303
328
  // eslint-disable-next-line no-param-reassign
304
- request = _url.default.fileURLToPath(originalUrl);
329
+ request = _url.default.fileURLToPath(originalRequest);
305
330
  } catch (ignoreError) {
331
+ // eslint-disable-next-line no-param-reassign
306
332
  request = request.slice(7);
307
333
  }
308
334
  }
309
335
 
310
336
  let resolutionMap = [];
311
337
  const needEmulateSassResolver = // `sass` doesn't support module import
312
- !isSpecialModuleImport.test(request) && // We need improve absolute paths handling.
338
+ !IS_SPECIAL_MODULE_IMPORT.test(request) && // We need improve absolute paths handling.
313
339
  // Absolute paths should be resolved:
314
340
  // - Server-relative URLs - `<context>/path/to/file.ext` (where `<context>` is root context)
315
341
  // - Absolute path - `/full/path/to/file.ext` or `C:\\full\path\to\file.ext`
316
- !isFileScheme && !originalUrl.startsWith('/') && !isNativeWin32Path.test(originalUrl);
342
+ !isFileScheme && !originalRequest.startsWith('/') && !IS_NATIVE_WIN32_PATH.test(originalRequest);
317
343
 
318
344
  if (includePaths.length > 0 && needEmulateSassResolver) {
319
345
  // The order of import precedence is as follows:
@@ -325,34 +351,54 @@ function getWebpackImporter(loaderContext, implementation, includePaths) {
325
351
  // 5. Filesystem imports relative to a `SASS_PATH` path.
326
352
  //
327
353
  // Because `sass`/`node-sass` run custom importers before `3`, `4` and `5` points, we need to emulate this behavior to avoid wrong resolution.
328
- const sassPossibleRequests = getPossibleRequests(loaderContext, request);
329
- const isDartSass = implementation.info.includes('dart-sass'); // `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`, so we need emulate this too
354
+ const sassPossibleRequests = getPossibleRequests(request); // `node-sass` calls our importer before `1. Filesystem imports relative to the base file.`, so we need emulate this too
330
355
 
331
356
  if (!isDartSass) {
332
357
  resolutionMap = resolutionMap.concat({
333
358
  resolve: sassResolve,
334
- context: _path.default.dirname(prev),
359
+ context: _path.default.dirname(context),
335
360
  possibleRequests: sassPossibleRequests
336
361
  });
337
362
  }
338
363
 
339
- resolutionMap = resolutionMap.concat(includePaths.map(context => ({
364
+ resolutionMap = resolutionMap.concat( // eslint-disable-next-line no-shadow
365
+ includePaths.map(context => ({
340
366
  resolve: sassResolve,
341
367
  context,
342
368
  possibleRequests: sassPossibleRequests
343
369
  })));
344
370
  }
345
371
 
346
- const webpackPossibleRequests = getPossibleRequests(loaderContext, request, true);
372
+ const webpackPossibleRequests = getPossibleRequests(request, true, rootContext);
347
373
  resolutionMap = resolutionMap.concat({
348
374
  resolve: webpackResolve,
349
- context: _path.default.dirname(prev),
375
+ context: _path.default.dirname(context),
350
376
  possibleRequests: webpackPossibleRequests
351
377
  });
352
- startResolving(resolutionMap) // Catch all resolving errors, return the original file and pass responsibility back to other custom importers
353
- .catch(() => ({
354
- file: originalUrl
355
- })).then(result => done(result));
378
+ return startResolving(resolutionMap);
379
+ };
380
+ }
381
+
382
+ const matchCss = /\.css$/i;
383
+
384
+ function getWebpackImporter(loaderContext, implementation, includePaths) {
385
+ const resolve = getWebpackResolver(loaderContext.getResolve, implementation, includePaths, loaderContext.rootContext);
386
+ return (originalUrl, prev, done) => {
387
+ resolve(prev, originalUrl).then(result => {
388
+ // Add the result as dependency.
389
+ // Although we're also using stats.includedFiles, this might come in handy when an error occurs.
390
+ // In this case, we don't get stats.includedFiles from node-sass/sass.
391
+ loaderContext.addDependency(_path.default.normalize(result)); // By removing the CSS file extension, we trigger node-sass to include the CSS file instead of just linking it.
392
+
393
+ done({
394
+ file: result.replace(matchCss, '')
395
+ });
396
+ }) // Catch all resolving errors, return the original file and pass responsibility back to other custom importers
397
+ .catch(() => {
398
+ done({
399
+ file: originalUrl
400
+ });
401
+ });
356
402
  };
357
403
  }
358
404
 
@@ -380,4 +426,46 @@ function getRenderFunctionFromSassImplementation(implementation) {
380
426
  }
381
427
 
382
428
  return nodeSassJobQueue.push.bind(nodeSassJobQueue);
429
+ }
430
+
431
+ const ABSOLUTE_SCHEME = /^[A-Za-z0-9+\-.]+:/;
432
+
433
+ function getURLType(source) {
434
+ if (source[0] === '/') {
435
+ if (source[1] === '/') {
436
+ return 'scheme-relative';
437
+ }
438
+
439
+ return 'path-absolute';
440
+ }
441
+
442
+ if (IS_NATIVE_WIN32_PATH.test(source)) {
443
+ return 'path-absolute';
444
+ }
445
+
446
+ return ABSOLUTE_SCHEME.test(source) ? 'absolute' : 'path-relative';
447
+ }
448
+
449
+ function normalizeSourceMap(map, rootContext) {
450
+ const newMap = map; // result.map.file is an optional property that provides the output filename.
451
+ // Since we don't know the final filename in the webpack build chain yet, it makes no sense to have it.
452
+ // eslint-disable-next-line no-param-reassign
453
+
454
+ delete newMap.file; // eslint-disable-next-line no-param-reassign
455
+
456
+ newMap.sourceRoot = ''; // node-sass returns POSIX paths, that's why we need to transform them back to native paths.
457
+ // This fixes an error on windows where the source-map module cannot resolve the source maps.
458
+ // @see https://github.com/webpack-contrib/sass-loader/issues/366#issuecomment-279460722
459
+ // eslint-disable-next-line no-param-reassign
460
+
461
+ newMap.sources = newMap.sources.map(source => {
462
+ const sourceType = getURLType(source); // Do no touch `scheme-relative`, `path-absolute` and `absolute` types
463
+
464
+ if (sourceType === 'path-relative') {
465
+ return _path.default.resolve(rootContext, _path.default.normalize(source));
466
+ }
467
+
468
+ return source;
469
+ });
470
+ return newMap;
383
471
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sass-loader",
3
- "version": "9.0.3",
3
+ "version": "10.0.2",
4
4
  "description": "Sass loader for webpack",
5
5
  "license": "MIT",
6
6
  "repository": "webpack-contrib/sass-loader",
@@ -56,43 +56,44 @@
56
56
  }
57
57
  },
58
58
  "dependencies": {
59
- "klona": "^1.1.2",
59
+ "klona": "^2.0.3",
60
60
  "loader-utils": "^2.0.0",
61
61
  "neo-async": "^2.6.2",
62
- "schema-utils": "^2.7.0",
62
+ "schema-utils": "^2.7.1",
63
63
  "semver": "^7.3.2"
64
64
  },
65
65
  "devDependencies": {
66
- "@babel/cli": "^7.10.5",
67
- "@babel/core": "^7.11.0",
68
- "@babel/preset-env": "^7.11.0",
69
- "@commitlint/cli": "^9.1.1",
70
- "@commitlint/config-conventional": "^9.1.1",
66
+ "@babel/cli": "^7.11.5",
67
+ "@babel/core": "^7.11.5",
68
+ "@babel/preset-env": "^7.11.5",
69
+ "@commitlint/cli": "^10.0.0",
70
+ "@commitlint/config-conventional": "^10.0.0",
71
71
  "@webpack-contrib/defaults": "^6.3.0",
72
72
  "@webpack-contrib/eslint-config-webpack": "^3.0.0",
73
- "babel-jest": "^26.2.2",
74
- "bootstrap": "^4.5.1",
73
+ "babel-jest": "^26.3.0",
74
+ "bootstrap": "^4.5.2",
75
75
  "bootstrap-sass": "^3.4.1",
76
76
  "cross-env": "^7.0.2",
77
- "css-loader": "^4.2.0",
77
+ "css-loader": "^4.2.2",
78
78
  "del": "^5.1.0",
79
79
  "del-cli": "^3.0.1",
80
- "eslint": "^7.6.0",
80
+ "enhanced-resolve": "^4.3.0",
81
+ "eslint": "^7.8.1",
81
82
  "eslint-config-prettier": "^6.11.0",
82
83
  "eslint-plugin-import": "^2.21.2",
83
84
  "fibers": "^5.0.0",
84
- "file-loader": "^6.0.0",
85
+ "file-loader": "^6.1.0",
85
86
  "foundation-sites": "^6.6.3",
86
87
  "husky": "^4.2.5",
87
- "jest": "^26.2.2",
88
- "lint-staged": "^10.2.11",
88
+ "jest": "^26.4.2",
89
+ "lint-staged": "^10.3.0",
89
90
  "material-components-web": "^7.0.0",
90
91
  "memfs": "^3.2.0",
91
92
  "node-sass": "^4.14.1",
92
93
  "npm-run-all": "^4.1.5",
93
- "prettier": "^2.0.5",
94
+ "prettier": "^2.1.1",
94
95
  "sass": "^1.26.10",
95
- "standard-version": "^8.0.2",
96
+ "standard-version": "^9.0.0",
96
97
  "style-loader": "^1.2.1",
97
98
  "webpack": "^4.44.1"
98
99
  },