css-loader 3.3.0 → 3.4.1

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,41 @@
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
+ ### [3.4.1](https://github.com/webpack-contrib/css-loader/compare/v3.4.0...v3.4.1) (2020-01-03)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * do not output `undefined` when sourceRoot is unavailable ([#1036](https://github.com/webpack-contrib/css-loader/issues/1036)) ([ded2a79](https://github.com/webpack-contrib/css-loader/commit/ded2a797271f2adf864bf92300621c024974bc79))
11
+ * don't output invalid es5 code when locals do not exists ([#1035](https://github.com/webpack-contrib/css-loader/issues/1035)) ([b60e62a](https://github.com/webpack-contrib/css-loader/commit/b60e62a655719cc1779fae7d577af6ad6cf42135))
12
+
13
+ ## [3.4.0](https://github.com/webpack-contrib/css-loader/compare/v3.3.1...v3.4.0) (2019-12-17)
14
+
15
+
16
+ ### Features
17
+
18
+ * `esModule` option ([#1026](https://github.com/webpack-contrib/css-loader/issues/1026)) ([d358cdb](https://github.com/webpack-contrib/css-loader/commit/d358cdbe2c026afafa0279003cb6c8a3eff4c419))
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * logic for order and media queries for imports ([#1018](https://github.com/webpack-contrib/css-loader/issues/1018)) ([65450d9](https://github.com/webpack-contrib/css-loader/commit/65450d9c04790ccc9fb06eac81ea6d8f3cdbfaac))
24
+
25
+ ### [3.3.2](https://github.com/webpack-contrib/css-loader/compare/v3.3.1...v3.3.2) (2019-12-12)
26
+
27
+
28
+ ### Bug Fixes
29
+
30
+ * logic for order and media queries for imports ([1fb5134](https://github.com/webpack-contrib/css-loader/commit/1fb51340a7719b6f5b517cb71ea85ec5d45c1199))
31
+
32
+ ### [3.3.1](https://github.com/webpack-contrib/css-loader/compare/v3.3.0...v3.3.1) (2019-12-12)
33
+
34
+
35
+ ### Bug Fixes
36
+
37
+ * better handling url functions and an url in `@import` at-rules
38
+ * reduce count of `require` ([#1014](https://github.com/webpack-contrib/css-loader/issues/1014)) ([e091d27](https://github.com/webpack-contrib/css-loader/commit/e091d2709c29ac57ed0106af8ec3b581cbda7a9c))
39
+
5
40
  ## [3.3.0](https://github.com/webpack-contrib/css-loader/compare/v3.2.1...v3.3.0) (2019-12-09)
6
41
 
7
42
 
package/README.md CHANGED
@@ -118,6 +118,7 @@ module.exports = {
118
118
  | **[`importLoaders`](#importloaders)** | `{Number}` | `0` | Enables/Disables or setups number of loaders applied before CSS loader |
119
119
  | **[`localsConvention`](#localsconvention)** | `{String}` | `'asIs'` | Style of exported classnames |
120
120
  | **[`onlyLocals`](#onlylocals)** | `{Boolean}` | `false` | Export only locals |
121
+ | **[`esModule`](#esmodule)** | `{Boolean}` | `false` | Use ES modules syntax |
121
122
 
122
123
  ### `url`
123
124
 
@@ -857,6 +858,34 @@ module.exports = {
857
858
  };
858
859
  ```
859
860
 
861
+ ### `esModule`
862
+
863
+ Type: `Boolean`
864
+ Default: `false`
865
+
866
+ By default, `css-loader` generates JS modules that use the CommonJS modules syntax.
867
+ There are some cases in which using ES modules is beneficial, like in the case of [module concatenation](https://webpack.js.org/plugins/module-concatenation-plugin/) and [tree shaking](https://webpack.js.org/guides/tree-shaking/).
868
+
869
+ You can enable a ES module syntax using:
870
+
871
+ **webpack.config.js**
872
+
873
+ ```js
874
+ module.exports = {
875
+ module: {
876
+ rules: [
877
+ {
878
+ test: /\.css$/i,
879
+ loader: 'css-loader',
880
+ options: {
881
+ esModule: true,
882
+ },
883
+ },
884
+ ],
885
+ },
886
+ };
887
+ ```
888
+
860
889
  ## Examples
861
890
 
862
891
  ### Assets
package/dist/index.js CHANGED
@@ -36,22 +36,7 @@ function loader(content, map, meta) {
36
36
  baseDataPath: 'options'
37
37
  });
38
38
  const callback = this.async();
39
- const sourceMap = options.sourceMap || false; // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
40
- // eslint-disable-next-line no-param-reassign
41
-
42
- map = sourceMap && map ? (0, _utils.normalizeSourceMap)(map) : null; // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
43
-
44
- if (meta) {
45
- const {
46
- ast
47
- } = meta;
48
-
49
- if (ast && ast.type === 'postcss' && ast.version === _package.default.version) {
50
- // eslint-disable-next-line no-param-reassign
51
- content = ast.root;
52
- }
53
- }
54
-
39
+ const sourceMap = options.sourceMap || false;
55
40
  const plugins = [];
56
41
 
57
42
  if (options.modules) {
@@ -71,13 +56,26 @@ function loader(content, map, meta) {
71
56
  plugins.push((0, _plugins.urlParser)({
72
57
  filter: (0, _utils.getFilter)(options.url, this.resourcePath, value => (0, _loaderUtils.isUrlRequest)(value))
73
58
  }));
59
+ } // Reuse CSS AST (PostCSS AST e.g 'postcss-loader') to avoid reparsing
60
+
61
+
62
+ if (meta) {
63
+ const {
64
+ ast
65
+ } = meta;
66
+
67
+ if (ast && ast.type === 'postcss' && ast.version === _package.default.version) {
68
+ // eslint-disable-next-line no-param-reassign
69
+ content = ast.root;
70
+ }
74
71
  }
75
72
 
76
73
  (0, _postcss.default)(plugins).process(content, {
77
74
  from: this.remainingRequest.split('!').pop(),
78
75
  to: this.currentRequest.split('!').pop(),
79
76
  map: options.sourceMap ? {
80
- prev: map,
77
+ // Some loaders (example `"postcss-loader": "1.x.x"`) always generates source map, we should remove it
78
+ prev: sourceMap && map ? (0, _utils.normalizeSourceMap)(map) : null,
81
79
  inline: false,
82
80
  annotation: false
83
81
  } : false
@@ -102,20 +100,17 @@ function loader(content, map, meta) {
102
100
  replacers.push(message.value);
103
101
  break;
104
102
  }
105
- } // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
106
-
107
-
108
- const apiCode = exportType === 'full' ? (0, _utils.getApiCode)(this, sourceMap) : '';
109
- const importCode = imports.length > 0 ? (0, _utils.getImportCode)(this, imports, {
110
- importLoaders: options.importLoaders,
111
- exportType
112
- }) : '';
113
- const moduleCode = exportType === 'full' ? (0, _utils.getModuleCode)(this, result, replacers, sourceMap) : '';
114
- const exportCode = exports.length > 0 ? (0, _utils.getExportCode)(this, exports, replacers, {
115
- localsConvention: options.localsConvention,
116
- exportType
117
- }) : '';
118
- return callback(null, [apiCode, importCode, moduleCode, exportCode].join(''));
103
+ }
104
+
105
+ const {
106
+ importLoaders,
107
+ localsConvention
108
+ } = options;
109
+ const esModule = typeof options.esModule !== 'undefined' ? options.esModule : false;
110
+ const importCode = (0, _utils.getImportCode)(this, imports, exportType, sourceMap, importLoaders, esModule);
111
+ const moduleCode = (0, _utils.getModuleCode)(this, result, exportType, sourceMap, replacers);
112
+ const exportCode = (0, _utils.getExportCode)(this, exports, exportType, replacers, localsConvention, esModule);
113
+ return callback(null, [importCode, moduleCode, exportCode].join(''));
119
114
  }).catch(error => {
120
115
  callback(error.name === 'CssSyntaxError' ? new _CssSyntaxError.default(error) : error);
121
116
  });
package/dist/options.json CHANGED
@@ -94,6 +94,10 @@
94
94
  "onlyLocals": {
95
95
  "description": "Export only locals (https://github.com/webpack-contrib/css-loader#onlylocals).",
96
96
  "type": "boolean"
97
+ },
98
+ "esModule": {
99
+ "description": "Use the ES modules syntax (https://github.com/webpack-contrib/css-loader#esmodule).",
100
+ "type": "boolean"
97
101
  }
98
102
  },
99
103
  "type": "object"
@@ -9,44 +9,68 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _icssUtils = require("icss-utils");
11
11
 
12
+ var _loaderUtils = require("loader-utils");
13
+
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
15
 
14
16
  const pluginName = 'postcss-icss-parser';
15
17
 
18
+ function normalizeIcssImports(icssImports) {
19
+ return Object.keys(icssImports).reduce((accumulator, url) => {
20
+ const tokensMap = icssImports[url];
21
+ const tokens = Object.keys(tokensMap);
22
+
23
+ if (tokens.length === 0) {
24
+ return accumulator;
25
+ }
26
+
27
+ const normalizedUrl = (0, _loaderUtils.urlToRequest)(url);
28
+
29
+ if (!accumulator[normalizedUrl]) {
30
+ // eslint-disable-next-line no-param-reassign
31
+ accumulator[normalizedUrl] = tokensMap;
32
+ } else {
33
+ // eslint-disable-next-line no-param-reassign
34
+ accumulator[normalizedUrl] = { ...accumulator[normalizedUrl],
35
+ ...tokensMap
36
+ };
37
+ }
38
+
39
+ return accumulator;
40
+ }, {});
41
+ }
42
+
16
43
  var _default = _postcss.default.plugin(pluginName, () => function process(css, result) {
17
44
  const importReplacements = Object.create(null);
18
45
  const {
19
46
  icssImports,
20
47
  icssExports
21
48
  } = (0, _icssUtils.extractICSS)(css);
22
- Object.keys(icssImports).forEach((url, importIndex) => {
23
- const tokens = Object.keys(icssImports[url]);
24
-
25
- if (tokens.length === 0) {
26
- return;
27
- }
28
-
49
+ const normalizedIcssImports = normalizeIcssImports(icssImports);
50
+ Object.keys(normalizedIcssImports).forEach((url, importIndex) => {
29
51
  const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;
30
52
  result.messages.push({
31
53
  pluginName,
32
54
  type: 'import',
33
55
  value: {
34
56
  type: 'icss-import',
35
- name: importName,
57
+ importName,
36
58
  url
37
59
  }
38
60
  });
61
+ const tokenMap = normalizedIcssImports[url];
62
+ const tokens = Object.keys(tokenMap);
39
63
  tokens.forEach((token, replacementIndex) => {
40
- const name = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
41
- const localName = icssImports[url][token];
42
- importReplacements[token] = name;
64
+ const replacementName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
65
+ const localName = tokenMap[token];
66
+ importReplacements[token] = replacementName;
43
67
  result.messages.push({
44
68
  pluginName,
45
69
  type: 'replacer',
46
70
  value: {
47
71
  type: 'icss-import',
48
- name,
49
72
  importName,
73
+ replacementName,
50
74
  localName
51
75
  }
52
76
  });
@@ -9,21 +9,33 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
11
 
12
+ var _loaderUtils = require("loader-utils");
13
+
14
+ var _utils = require("../utils");
15
+
12
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
17
 
14
18
  const pluginName = 'postcss-import-parser';
15
19
 
16
- function getArg(nodes) {
17
- return nodes.length !== 0 && nodes[0].type === 'string' ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
18
- }
19
-
20
- function getUrl(node) {
20
+ function getParsedValue(node) {
21
21
  if (node.type === 'function' && node.value.toLowerCase() === 'url') {
22
- return getArg(node.nodes);
22
+ const {
23
+ nodes
24
+ } = node;
25
+ const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
26
+ const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
27
+ return {
28
+ url,
29
+ isStringValue
30
+ };
23
31
  }
24
32
 
25
33
  if (node.type === 'string') {
26
- return node.value;
34
+ const url = node.value;
35
+ return {
36
+ url,
37
+ isStringValue: true
38
+ };
27
39
  }
28
40
 
29
41
  return null;
@@ -38,12 +50,27 @@ function parseImport(params) {
38
50
  return null;
39
51
  }
40
52
 
41
- const url = getUrl(nodes[0]);
53
+ const value = getParsedValue(nodes[0]);
54
+
55
+ if (!value) {
56
+ return null;
57
+ }
58
+
59
+ let {
60
+ url
61
+ } = value;
42
62
 
43
- if (!url || url.trim().length === 0) {
63
+ if (url.trim().length === 0) {
44
64
  return null;
45
65
  }
46
66
 
67
+ if ((0, _loaderUtils.isUrlRequest)(url)) {
68
+ const {
69
+ isStringValue
70
+ } = value;
71
+ url = (0, _utils.normalizeUrl)(url, isStringValue);
72
+ }
73
+
47
74
  return {
48
75
  url,
49
76
  media: _postcssValueParser.default.stringify(nodes.slice(1)).trim().toLowerCase()
@@ -51,7 +78,7 @@ function parseImport(params) {
51
78
  }
52
79
 
53
80
  function walkAtRules(css, result, filter) {
54
- const items = new Map();
81
+ const items = [];
55
82
  css.walkAtRules(/^import$/i, atRule => {
56
83
  // Convert only top-level @import
57
84
  if (atRule.parent.type !== 'root') {
@@ -79,44 +106,23 @@ function walkAtRules(css, result, filter) {
79
106
  }
80
107
 
81
108
  atRule.remove();
82
- const {
83
- url,
84
- media
85
- } = parsed;
86
- const value = items.get(url);
87
-
88
- if (!value) {
89
- items.set(url, new Set([media]));
90
- } else {
91
- value.add(media);
92
- }
109
+ items.push(parsed);
93
110
  });
94
111
  return items;
95
112
  }
96
113
 
97
114
  var _default = _postcss.default.plugin(pluginName, options => function process(css, result) {
98
115
  const items = walkAtRules(css, result, options.filter);
99
- [...items].reduce((accumulator, currentValue) => {
100
- const [url, medias] = currentValue;
101
- medias.forEach(media => {
102
- accumulator.push({
103
- url,
104
- media
105
- });
106
- });
107
- return accumulator;
108
- }, []).forEach((item, index) => {
116
+ items.forEach(item => {
109
117
  const {
110
118
  url,
111
119
  media
112
120
  } = item;
113
- const name = `___CSS_LOADER_AT_RULE_IMPORT_${index}___`;
114
121
  result.messages.push({
115
122
  pluginName,
116
123
  type: 'import',
117
124
  value: {
118
125
  type: '@import',
119
- name,
120
126
  url,
121
127
  media
122
128
  }
@@ -9,6 +9,8 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
11
 
12
+ var _utils = require("../utils");
13
+
12
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
15
 
14
16
  const pluginName = 'postcss-url-parser';
@@ -20,10 +22,6 @@ function getNodeFromUrlFunc(node) {
20
22
  return node.nodes && node.nodes[0];
21
23
  }
22
24
 
23
- function getUrlFromUrlFunc(node) {
24
- return node.nodes.length !== 0 && node.nodes[0].type === 'string' ? node.nodes[0].value : _postcssValueParser.default.stringify(node.nodes);
25
- }
26
-
27
25
  function walkUrls(parsed, callback) {
28
26
  parsed.walk(node => {
29
27
  if (node.type !== 'function') {
@@ -31,7 +29,12 @@ function walkUrls(parsed, callback) {
31
29
  }
32
30
 
33
31
  if (isUrlFunc.test(node.value)) {
34
- callback(getNodeFromUrlFunc(node), getUrlFromUrlFunc(node), false); // Do not traverse inside `url`
32
+ const {
33
+ nodes
34
+ } = node;
35
+ const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
36
+ const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
37
+ callback(getNodeFromUrlFunc(node), url, false, isStringValue); // Do not traverse inside `url`
35
38
  // eslint-disable-next-line consistent-return
36
39
 
37
40
  return false;
@@ -39,12 +42,22 @@ function walkUrls(parsed, callback) {
39
42
 
40
43
  if (isImageSetFunc.test(node.value)) {
41
44
  node.nodes.forEach(nNode => {
42
- if (nNode.type === 'function' && isUrlFunc.test(nNode.value)) {
43
- callback(getNodeFromUrlFunc(nNode), getUrlFromUrlFunc(nNode), false);
45
+ const {
46
+ type,
47
+ value
48
+ } = nNode;
49
+
50
+ if (type === 'function' && isUrlFunc.test(value)) {
51
+ const {
52
+ nodes
53
+ } = nNode;
54
+ const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
55
+ const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
56
+ callback(getNodeFromUrlFunc(nNode), url, false, isStringValue);
44
57
  }
45
58
 
46
- if (nNode.type === 'string') {
47
- callback(nNode, nNode.value, true);
59
+ if (type === 'string') {
60
+ callback(nNode, value, true, true);
48
61
  }
49
62
  }); // Do not traverse inside `image-set`
50
63
  // eslint-disable-next-line consistent-return
@@ -61,7 +74,7 @@ function getUrlsFromValue(value, result, filter, decl) {
61
74
 
62
75
  const parsed = (0, _postcssValueParser.default)(value);
63
76
  const urls = [];
64
- walkUrls(parsed, (node, url, needQuotes) => {
77
+ walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
65
78
  if (url.trim().replace(/\\[\r\n]/g, '').length === 0) {
66
79
  result.warn(`Unable to find uri in '${decl ? decl.toString() : value}'`, {
67
80
  node: decl
@@ -73,8 +86,10 @@ function getUrlsFromValue(value, result, filter, decl) {
73
86
  return;
74
87
  }
75
88
 
76
- const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
89
+ const splittedUrl = url.split(/(\?)?#/);
90
+ const [urlWithoutHash, singleQuery, hashValue] = splittedUrl;
77
91
  const hash = singleQuery || hashValue ? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}` : '';
92
+ const normalizedUrl = (0, _utils.normalizeUrl)(urlWithoutHash, isStringValue);
78
93
  urls.push({
79
94
  node,
80
95
  url: normalizedUrl,
@@ -138,51 +153,51 @@ function collectUniqueUrlsWithNodes(array) {
138
153
 
139
154
  var _default = _postcss.default.plugin(pluginName, options => function process(css, result) {
140
155
  const traversed = walkDecls(css, result, options.filter);
141
- const paths = collectUniqueUrlsWithNodes(flatten(traversed.map(item => item.urls)));
156
+ const flattenTraversed = flatten(traversed.map(item => item.urls));
157
+ const urlsWithNodes = collectUniqueUrlsWithNodes(flattenTraversed);
142
158
  const replacers = new Map();
143
- paths.forEach((path, index) => {
159
+ urlsWithNodes.forEach((urlWithNodes, index) => {
144
160
  const {
145
161
  url,
146
162
  hash,
147
163
  needQuotes,
148
164
  nodes
149
- } = path;
150
- const name = `___CSS_LOADER_URL_IMPORT_${index}___`;
165
+ } = urlWithNodes;
166
+ const replacementName = `___CSS_LOADER_URL_REPLACEMENT_${index}___`;
151
167
  result.messages.push({
152
168
  pluginName,
153
169
  type: 'import',
154
170
  value: {
155
171
  type: 'url',
156
- name,
172
+ replacementName,
157
173
  url,
158
174
  needQuotes,
159
- hash,
160
- index
175
+ hash
161
176
  }
162
177
  }, {
163
178
  pluginName,
164
179
  type: 'replacer',
165
180
  value: {
166
181
  type: 'url',
167
- name
182
+ replacementName
168
183
  }
169
184
  });
170
185
  nodes.forEach(node => {
171
- replacers.set(node, name);
186
+ replacers.set(node, replacementName);
172
187
  });
173
188
  });
174
189
  traversed.forEach(item => {
175
190
  walkUrls(item.parsed, node => {
176
- const name = replacers.get(node);
191
+ const replacementName = replacers.get(node);
177
192
 
178
- if (!name) {
193
+ if (!replacementName) {
179
194
  return;
180
195
  } // eslint-disable-next-line no-param-reassign
181
196
 
182
197
 
183
198
  node.type = 'word'; // eslint-disable-next-line no-param-reassign
184
199
 
185
- node.value = name;
200
+ node.value = replacementName;
186
201
  }); // eslint-disable-next-line no-param-reassign
187
202
 
188
203
  item.decl.value = item.parsed.toString();
@@ -14,7 +14,7 @@ module.exports = function (useSourceMap) {
14
14
  var content = cssWithMappingToString(item, useSourceMap);
15
15
 
16
16
  if (item[2]) {
17
- return "@media ".concat(item[2], "{").concat(content, "}");
17
+ return "@media ".concat(item[2], " {").concat(content, "}");
18
18
  }
19
19
 
20
20
  return content;
@@ -29,32 +29,18 @@ module.exports = function (useSourceMap) {
29
29
  modules = [[null, modules, '']];
30
30
  }
31
31
 
32
- var alreadyImportedModules = {};
32
+ for (var i = 0; i < modules.length; i++) {
33
+ var item = [].concat(modules[i]);
33
34
 
34
- for (var i = 0; i < this.length; i++) {
35
- // eslint-disable-next-line prefer-destructuring
36
- var id = this[i][0];
37
-
38
- if (id != null) {
39
- alreadyImportedModules[id] = true;
40
- }
41
- }
42
-
43
- for (var _i = 0; _i < modules.length; _i++) {
44
- var item = modules[_i]; // skip already imported module
45
- // this implementation is not 100% perfect for weird media query combinations
46
- // when a module is imported multiple times with different media queries.
47
- // I hope this will never occur (Hey this way we have smaller bundles)
48
-
49
- if (item[0] == null || !alreadyImportedModules[item[0]]) {
50
- if (mediaQuery && !item[2]) {
35
+ if (mediaQuery) {
36
+ if (!item[2]) {
51
37
  item[2] = mediaQuery;
52
- } else if (mediaQuery) {
53
- item[2] = "(".concat(item[2], ") and (").concat(mediaQuery, ")");
38
+ } else {
39
+ item[2] = "".concat(mediaQuery, " and ").concat(item[2]);
54
40
  }
55
-
56
- list.push(item);
57
41
  }
42
+
43
+ list.push(item);
58
44
  }
59
45
  };
60
46
 
@@ -73,7 +59,7 @@ function cssWithMappingToString(item, useSourceMap) {
73
59
  if (useSourceMap && typeof btoa === 'function') {
74
60
  var sourceMapping = toComment(cssMapping);
75
61
  var sourceURLs = cssMapping.sources.map(function (source) {
76
- return "/*# sourceURL=".concat(cssMapping.sourceRoot).concat(source, " */");
62
+ return "/*# sourceURL=".concat(cssMapping.sourceRoot || '').concat(source, " */");
77
63
  });
78
64
  return [content].concat(sourceURLs).concat([sourceMapping]).join('\n');
79
65
  }
package/dist/utils.js CHANGED
@@ -3,10 +3,10 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.normalizeUrl = normalizeUrl;
6
7
  exports.getFilter = getFilter;
7
8
  exports.getModulesPlugins = getModulesPlugins;
8
9
  exports.normalizeSourceMap = normalizeSourceMap;
9
- exports.getApiCode = getApiCode;
10
10
  exports.getImportCode = getImportCode;
11
11
  exports.getModuleCode = getModuleCode;
12
12
  exports.getExportCode = getExportCode;
@@ -39,16 +39,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
39
39
  MIT License http://www.opensource.org/licenses/mit-license.php
40
40
  Author Tobias Koppers @sokra
41
41
  */
42
- function getImportPrefix(loaderContext, importLoaders) {
43
- if (importLoaders === false) {
44
- return '';
45
- }
46
-
47
- const numberImportedLoaders = parseInt(importLoaders, 10) || 0;
48
- const loadersRequest = loaderContext.loaders.slice(loaderContext.loaderIndex, loaderContext.loaderIndex + 1 + numberImportedLoaders).map(x => x.request).join('!');
49
- return `-!${loadersRequest}!`;
50
- }
51
-
52
42
  const whitespace = '[\\x20\\t\\r\\n\\f]';
53
43
  const unescapeRegExp = new RegExp(`\\\\([\\da-f]{1,6}${whitespace}?|(${whitespace})|.)`, 'ig');
54
44
 
@@ -91,6 +81,16 @@ function getLocalIdent(loaderContext, localIdentName, localName, options) {
91
81
  }).replace(/\\\[local\\\]/gi, localName);
92
82
  }
93
83
 
84
+ function normalizeUrl(url, isStringValue) {
85
+ let normalizedUrl = url;
86
+
87
+ if (isStringValue && /\\[\n]/.test(normalizedUrl)) {
88
+ normalizedUrl = normalizedUrl.replace(/\\[\n]/g, '');
89
+ }
90
+
91
+ return (0, _loaderUtils.urlToRequest)(decodeURIComponent(unescape(normalizedUrl)));
92
+ }
93
+
94
94
  function getFilter(filter, resourcePath, defaultFilter = null) {
95
95
  return item => {
96
96
  if (defaultFilter && !defaultFilter(item)) {
@@ -148,7 +148,7 @@ function normalizeSourceMap(map) {
148
148
  // Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification), and then parse the string as JSON.
149
149
 
150
150
  if (typeof newMap === 'string') {
151
- newMap = JSON.parse(newMap.replace(/^\)]}'[^\n]*\n/, ''));
151
+ newMap = JSON.parse(newMap);
152
152
  } // Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91)
153
153
  // We should normalize path because previous loaders like `sass-loader` using backslash when generate source map
154
154
 
@@ -168,73 +168,117 @@ function normalizeSourceMap(map) {
168
168
  return newMap;
169
169
  }
170
170
 
171
- function getApiCode(loaderContext, sourceMap) {
172
- const url = (0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/api'));
173
- return `exports = module.exports = require(${url})(${sourceMap});\n`;
171
+ function getImportPrefix(loaderContext, importLoaders) {
172
+ if (importLoaders === false) {
173
+ return '';
174
+ }
175
+
176
+ const numberImportedLoaders = parseInt(importLoaders, 10) || 0;
177
+ const loadersRequest = loaderContext.loaders.slice(loaderContext.loaderIndex, loaderContext.loaderIndex + 1 + numberImportedLoaders).map(x => x.request).join('!');
178
+ return `-!${loadersRequest}!`;
174
179
  }
175
180
 
176
- function getImportCode(loaderContext, imports, options) {
181
+ function getImportCode(loaderContext, imports, exportType, sourceMap, importLoaders, esModule) {
177
182
  const importItems = [];
178
183
  const codeItems = [];
184
+ const atRuleImportNames = new Map();
179
185
  const urlImportNames = new Map();
180
- let hasUrlHelperCode = false;
181
186
  let importPrefix;
187
+
188
+ if (exportType === 'full') {
189
+ importItems.push(esModule ? `import ___CSS_LOADER_API_IMPORT___ from ${(0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/api'))};` : `var ___CSS_LOADER_API_IMPORT___ = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/api'))});`);
190
+ codeItems.push(esModule ? `var exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});` : `exports = ___CSS_LOADER_API_IMPORT___(${sourceMap});`);
191
+ }
192
+
182
193
  imports.forEach(item => {
183
- if (item.type === '@import' || item.type === 'icss-import') {
184
- const media = item.media ? `, ${JSON.stringify(item.media)}` : '';
194
+ // eslint-disable-next-line default-case
195
+ switch (item.type) {
196
+ case '@import':
197
+ {
198
+ const {
199
+ url,
200
+ media
201
+ } = item;
202
+ const preparedMedia = media ? `, ${JSON.stringify(media)}` : '';
203
+
204
+ if (!(0, _loaderUtils.isUrlRequest)(url)) {
205
+ codeItems.push(`exports.push([module.id, ${JSON.stringify(`@import url(${url});`)}${preparedMedia}]);`);
206
+ return;
207
+ }
185
208
 
186
- if (!(0, _loaderUtils.isUrlRequest)(item.url)) {
187
- const url = JSON.stringify(`@import url(${item.url});`);
188
- codeItems.push(`exports.push([module.id, ${url}${media}]);`);
189
- return;
190
- }
209
+ let importName = atRuleImportNames.get(url);
191
210
 
192
- if (!importPrefix) {
193
- importPrefix = getImportPrefix(loaderContext, options.importLoaders);
194
- }
211
+ if (!importName) {
212
+ if (!importPrefix) {
213
+ importPrefix = getImportPrefix(loaderContext, importLoaders);
214
+ }
195
215
 
196
- const url = (0, _loaderUtils.stringifyRequest)(loaderContext, importPrefix + (0, _loaderUtils.urlToRequest)(item.url));
197
- importItems.push(`var ${item.name} = require(${url});`);
216
+ importName = `___CSS_LOADER_AT_RULE_IMPORT_${atRuleImportNames.size}___`;
217
+ importItems.push(esModule ? `import ${importName} from ${(0, _loaderUtils.stringifyRequest)(loaderContext, importPrefix + url)};` : `var ${importName} = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, importPrefix + url)});`);
218
+ atRuleImportNames.set(url, importName);
219
+ }
198
220
 
199
- if (options.exportType === 'full') {
200
- codeItems.push(`exports.i(${item.name}${media});`);
201
- }
202
- }
221
+ codeItems.push(`exports.i(${importName}${preparedMedia});`);
222
+ }
223
+ break;
203
224
 
204
- if (item.type === 'url') {
205
- if (!hasUrlHelperCode) {
206
- const pathToGetUrl = require.resolve('./runtime/getUrl.js');
225
+ case 'url':
226
+ {
227
+ if (urlImportNames.size === 0) {
228
+ importItems.push(esModule ? `import ___CSS_LOADER_GET_URL_IMPORT___ from ${(0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/getUrl.js'))};` : `var ___CSS_LOADER_GET_URL_IMPORT___ = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/getUrl.js'))});`);
229
+ }
207
230
 
208
- const url = (0, _loaderUtils.stringifyRequest)(loaderContext, pathToGetUrl);
209
- importItems.push(`var ___CSS_LOADER_GET_URL_IMPORT___ = require(${url});`);
210
- hasUrlHelperCode = true;
211
- }
231
+ const {
232
+ replacementName,
233
+ url,
234
+ hash,
235
+ needQuotes
236
+ } = item;
237
+ let importName = urlImportNames.get(url);
238
+
239
+ if (!importName) {
240
+ importName = `___CSS_LOADER_URL_IMPORT_${urlImportNames.size}___`;
241
+ importItems.push(esModule ? `import ${importName} from ${(0, _loaderUtils.stringifyRequest)(loaderContext, url)};` : `var ${importName} = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, url)});`);
242
+ urlImportNames.set(url, importName);
243
+ }
212
244
 
213
- const {
214
- name,
215
- url,
216
- hash,
217
- needQuotes,
218
- index
219
- } = item;
220
- let importName = urlImportNames.get(url);
245
+ const getUrlOptions = [].concat(hash ? [`hash: ${JSON.stringify(hash)}`] : []).concat(needQuotes ? 'needQuotes: true' : []);
246
+ const preparedOptions = getUrlOptions.length > 0 ? `, { ${getUrlOptions.join(', ')} }` : '';
247
+ codeItems.push(`var ${replacementName} = ___CSS_LOADER_GET_URL_IMPORT___(${importName}${preparedOptions});`);
248
+ }
249
+ break;
221
250
 
222
- if (!importName) {
223
- const preparedUrl = (0, _loaderUtils.stringifyRequest)(loaderContext, (0, _loaderUtils.urlToRequest)(url));
224
- importName = `___CSS_LOADER_URL_PURE_IMPORT_${index}___`;
225
- importItems.push(`var ${importName} = require(${preparedUrl});`);
226
- urlImportNames.set(url, importName);
227
- }
251
+ case 'icss-import':
252
+ {
253
+ const {
254
+ importName,
255
+ url,
256
+ media
257
+ } = item;
258
+ const preparedMedia = media ? `, ${JSON.stringify(media)}` : '';
259
+
260
+ if (!importPrefix) {
261
+ importPrefix = getImportPrefix(loaderContext, importLoaders);
262
+ }
263
+
264
+ importItems.push(esModule ? `import ${importName} from ${(0, _loaderUtils.stringifyRequest)(loaderContext, importPrefix + url)};` : `var ${importName} = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, importPrefix + url)});`);
228
265
 
229
- const getUrlOptions = [].concat(hash ? [`hash: ${JSON.stringify(hash)}`] : []).concat(needQuotes ? 'needQuotes: true' : []);
230
- const preparedOptions = getUrlOptions.length > 0 ? `, { ${getUrlOptions.join(', ')} }` : '';
231
- codeItems.push(`var ${name} = ___CSS_LOADER_GET_URL_IMPORT___(${importName}${preparedOptions});`);
266
+ if (exportType === 'full') {
267
+ codeItems.push(`exports.i(${importName}${preparedMedia});`);
268
+ }
269
+ }
270
+ break;
232
271
  }
233
272
  });
234
- return `// Imports\n${importItems.join('\n')}\n${codeItems.join('\n')}\n`;
273
+ const items = importItems.concat(codeItems);
274
+ return items.length > 0 ? `// Imports\n${items.join('\n')}\n` : '';
235
275
  }
236
276
 
237
- function getModuleCode(loaderContext, result, replacers, sourceMap) {
277
+ function getModuleCode(loaderContext, result, exportType, sourceMap, replacers) {
278
+ if (exportType !== 'full') {
279
+ return '';
280
+ }
281
+
238
282
  const {
239
283
  css,
240
284
  map
@@ -244,11 +288,11 @@ function getModuleCode(loaderContext, result, replacers, sourceMap) {
244
288
  replacers.forEach(replacer => {
245
289
  const {
246
290
  type,
247
- name
291
+ replacementName
248
292
  } = replacer;
249
293
 
250
294
  if (type === 'url') {
251
- cssCode = cssCode.replace(new RegExp(name, 'g'), () => `" + ${name} + "`);
295
+ cssCode = cssCode.replace(new RegExp(replacementName, 'g'), () => `" + ${replacementName} + "`);
252
296
  }
253
297
 
254
298
  if (type === 'icss-import') {
@@ -256,7 +300,7 @@ function getModuleCode(loaderContext, result, replacers, sourceMap) {
256
300
  importName,
257
301
  localName
258
302
  } = replacer;
259
- cssCode = cssCode.replace(new RegExp(name, 'g'), () => `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
303
+ cssCode = cssCode.replace(new RegExp(replacementName, 'g'), () => `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
260
304
  }
261
305
  });
262
306
  return `// Module\nexports.push([module.id, ${cssCode}, ""${sourceMapValue}]);\n`;
@@ -266,72 +310,88 @@ function dashesCamelCase(str) {
266
310
  return str.replace(/-+(\w)/g, (match, firstLetter) => firstLetter.toUpperCase());
267
311
  }
268
312
 
269
- function getExportCode(loaderContext, exports, replacers, options) {
270
- const items = [];
313
+ function getExportCode(loaderContext, exports, exportType, replacers, localsConvention, esModule) {
314
+ const exportItems = [];
315
+ let exportLocalsCode;
271
316
 
272
- function addExportedItem(name, value) {
273
- items.push(`\t${JSON.stringify(name)}: ${JSON.stringify(value)}`);
274
- }
317
+ if (exports.length > 0) {
318
+ const exportLocals = [];
275
319
 
276
- exports.forEach(item => {
277
- const {
278
- name,
279
- value
280
- } = item;
320
+ const addExportedLocal = (name, value) => {
321
+ exportLocals.push(`\t${JSON.stringify(name)}: ${JSON.stringify(value)}`);
322
+ };
281
323
 
282
- switch (options.localsConvention) {
283
- case 'camelCase':
284
- {
285
- addExportedItem(name, value);
286
- const modifiedName = (0, _camelcase.default)(name);
324
+ exports.forEach(item => {
325
+ const {
326
+ name,
327
+ value
328
+ } = item;
329
+
330
+ switch (localsConvention) {
331
+ case 'camelCase':
332
+ {
333
+ addExportedLocal(name, value);
334
+ const modifiedName = (0, _camelcase.default)(name);
335
+
336
+ if (modifiedName !== name) {
337
+ addExportedLocal(modifiedName, value);
338
+ }
287
339
 
288
- if (modifiedName !== name) {
289
- addExportedItem(modifiedName, value);
340
+ break;
290
341
  }
291
342
 
292
- break;
293
- }
343
+ case 'camelCaseOnly':
344
+ {
345
+ addExportedLocal((0, _camelcase.default)(name), value);
346
+ break;
347
+ }
294
348
 
295
- case 'camelCaseOnly':
296
- {
297
- addExportedItem((0, _camelcase.default)(name), value);
298
- break;
299
- }
349
+ case 'dashes':
350
+ {
351
+ addExportedLocal(name, value);
352
+ const modifiedName = dashesCamelCase(name);
300
353
 
301
- case 'dashes':
302
- {
303
- addExportedItem(name, value);
304
- const modifiedName = dashesCamelCase(name);
354
+ if (modifiedName !== name) {
355
+ addExportedLocal(modifiedName, value);
356
+ }
305
357
 
306
- if (modifiedName !== name) {
307
- addExportedItem(modifiedName, value);
358
+ break;
308
359
  }
309
360
 
310
- break;
311
- }
361
+ case 'dashesOnly':
362
+ {
363
+ addExportedLocal(dashesCamelCase(name), value);
364
+ break;
365
+ }
312
366
 
313
- case 'dashesOnly':
314
- {
315
- addExportedItem(dashesCamelCase(name), value);
367
+ case 'asIs':
368
+ default:
369
+ addExportedLocal(name, value);
316
370
  break;
317
- }
371
+ }
372
+ });
373
+ exportLocalsCode = exportLocals.join(',\n');
374
+ replacers.forEach(replacer => {
375
+ if (replacer.type === 'icss-import') {
376
+ const {
377
+ replacementName,
378
+ importName,
379
+ localName
380
+ } = replacer;
381
+ exportLocalsCode = exportLocalsCode.replace(new RegExp(replacementName, 'g'), () => exportType === 'locals' ? `" + ${importName}[${JSON.stringify(localName)}] + "` : `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
382
+ }
383
+ });
384
+ }
318
385
 
319
- case 'asIs':
320
- default:
321
- addExportedItem(name, value);
322
- break;
323
- }
324
- });
325
- let exportCode = `// Exports\n${options.exportType === 'locals' ? 'module.exports' : 'exports.locals'} = {\n${items.join(',\n')}\n};`;
326
- replacers.forEach(replacer => {
327
- if (replacer.type === 'icss-import') {
328
- const {
329
- name,
330
- importName
331
- } = replacer;
332
- const localName = JSON.stringify(replacer.localName);
333
- exportCode = exportCode.replace(new RegExp(name, 'g'), () => options.exportType === 'locals' ? `" + ${importName}[${localName}] + "` : `" + ${importName}.locals[${localName}] + "`);
386
+ if (exportType === 'locals') {
387
+ exportItems.push(`${esModule ? 'export default' : 'module.exports ='} ${exportLocalsCode ? `{\n${exportLocalsCode}\n}` : '{}'};`);
388
+ } else {
389
+ if (exportLocalsCode) {
390
+ exportItems.push(`exports.locals = {\n${exportLocalsCode}\n};`);
334
391
  }
335
- });
336
- return exportCode;
392
+
393
+ exportItems.push(`${esModule ? 'export default' : 'module.exports ='} exports;`);
394
+ }
395
+
396
+ return `// Exports\n${exportItems.join('\n')}\n`;
337
397
  }
package/package.json CHANGED
@@ -1,44 +1,46 @@
1
1
  {
2
2
  "name": "css-loader",
3
- "version": "3.3.0",
3
+ "version": "3.4.1",
4
4
  "description": "css loader module for webpack",
5
5
  "license": "MIT",
6
6
  "repository": "webpack-contrib/css-loader",
7
7
  "author": "Tobias Koppers @sokra",
8
8
  "homepage": "https://github.com/webpack-contrib/css-loader",
9
9
  "bugs": "https://github.com/webpack-contrib/css-loader/issues",
10
+ "funding": {
11
+ "type": "opencollective",
12
+ "url": "https://opencollective.com/webpack"
13
+ },
10
14
  "main": "dist/cjs.js",
11
15
  "engines": {
12
16
  "node": ">= 8.9.0"
13
17
  },
14
18
  "scripts": {
15
19
  "start": "npm run build -- -w",
16
- "prebuild": "npm run clean",
17
- "build": "cross-env NODE_ENV=production babel src -d dist --ignore \"src/**/*.test.js\" --copy-files",
20
+ "clean": "del-cli dist",
18
21
  "validate:runtime": "es-check es5 \"dist/runtime/**/*.js\"",
22
+ "prebuild": "npm run clean",
23
+ "build": "cross-env NODE_ENV=production babel src -d dist --copy-files",
19
24
  "postbuild": "npm run validate:runtime",
20
- "clean": "del-cli dist",
21
25
  "commitlint": "commitlint --from=master",
22
- "lint:prettier": "prettier \"{**/*,*}.{js,json,md,yml,css}\" --list-different",
23
- "lint:js": "eslint --cache src test",
24
- "lint": "npm-run-all -l -p \"lint:**\"",
25
- "prepare": "npm run build",
26
- "release": "standard-version",
27
26
  "security": "npm audit",
27
+ "lint:prettier": "prettier \"{**/*,*}.{js,json,md,yml,css,ts}\" --list-different",
28
+ "lint:js": "eslint --cache .",
29
+ "lint": "npm-run-all -l -p \"lint:**\"",
28
30
  "test:only": "cross-env NODE_ENV=test jest",
29
- "test:watch": "cross-env NODE_ENV=test jest --watch",
30
- "test:coverage": "cross-env NODE_ENV=test jest --collectCoverageFrom=\"src/**/*.js\" --coverage",
31
+ "test:watch": "npm run test:only -- --watch",
32
+ "test:coverage": "npm run test:only -- --collectCoverageFrom=\"src/**/*.js\" --coverage",
31
33
  "pretest": "npm run lint",
32
- "test": "cross-env NODE_ENV=test npm run test:coverage",
34
+ "test": "npm run test:coverage",
35
+ "prepare": "npm run build",
36
+ "release": "standard-version",
33
37
  "defaults": "webpack-defaults"
34
38
  },
35
39
  "files": [
36
- "dist/",
37
- "lib/",
38
- "index.js"
40
+ "dist"
39
41
  ],
40
42
  "peerDependencies": {
41
- "webpack": "^4.0.0"
43
+ "webpack": "^4.0.0 || ^5.0.0"
42
44
  },
43
45
  "dependencies": {
44
46
  "camelcase": "^5.3.1",
@@ -60,7 +62,7 @@
60
62
  "@babel/preset-env": "^7.7.4",
61
63
  "@commitlint/cli": "^8.2.0",
62
64
  "@commitlint/config-conventional": "^8.2.0",
63
- "@webpack-contrib/defaults": "^5.0.2",
65
+ "@webpack-contrib/defaults": "^6.3.0",
64
66
  "@webpack-contrib/eslint-config-webpack": "^3.0.0",
65
67
  "babel-jest": "^24.9.0",
66
68
  "commitlint-azure-pipelines-cli": "^1.0.2",
@@ -74,9 +76,9 @@
74
76
  "file-loader": "^5.0.2",
75
77
  "husky": "^3.1.0",
76
78
  "jest": "^24.9.0",
77
- "jest-junit": "^9.0.0",
79
+ "jest-junit": "^10.0.0",
78
80
  "lint-staged": "^9.5.0",
79
- "memory-fs": "^0.5.0",
81
+ "memfs": "^3.0.1",
80
82
  "npm-run-all": "^4.1.5",
81
83
  "postcss-loader": "^3.0.0",
82
84
  "postcss-preset-env": "^6.7.0",
@@ -86,7 +88,7 @@
86
88
  "standard-version": "^7.0.1",
87
89
  "strip-ansi": "^6.0.0",
88
90
  "url-loader": "^3.0.0",
89
- "webpack": "^4.41.2"
91
+ "webpack": "^4.41.3"
90
92
  },
91
93
  "keywords": [
92
94
  "webpack",