css-loader 3.2.1 → 3.3.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/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
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.3.0](https://github.com/webpack-contrib/css-loader/compare/v3.2.1...v3.3.0) (2019-12-09)
6
+
7
+
8
+ ### Features
9
+
10
+ * support `pure` css modules ([#1008](https://github.com/webpack-contrib/css-loader/issues/1008)) ([6177af5](https://github.com/webpack-contrib/css-loader/commit/6177af5596566fead13a8f66d5abcb4dc2b744db))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * do not crash when an assert return `null` or `undefined` ([#1006](https://github.com/webpack-contrib/css-loader/issues/1006)) ([6769783](https://github.com/webpack-contrib/css-loader/commit/67697833725e1cff12a14663390bbe4c65ea36d2))
16
+ * reduce count of `require` ([#1004](https://github.com/webpack-contrib/css-loader/issues/1004)) ([80e9662](https://github.com/webpack-contrib/css-loader/commit/80e966280f2477c5c0e4553d3be3a04511fea381))
17
+
5
18
  ### [3.2.1](https://github.com/webpack-contrib/css-loader/compare/v3.2.0...v3.2.1) (2019-12-02)
6
19
 
7
20
 
package/README.md CHANGED
@@ -317,6 +317,7 @@ module.exports = {
317
317
 
318
318
  Using `local` value requires you to specify `:global` classes.
319
319
  Using `global` value requires you to specify `:local` classes.
320
+ Using `pure` value requires selectors must contain at least one local class or id.
320
321
 
321
322
  You can find more information [here](https://github.com/css-modules/css-modules).
322
323
 
package/dist/index.js CHANGED
@@ -56,27 +56,19 @@ function loader(content, map, meta) {
56
56
 
57
57
  if (options.modules) {
58
58
  plugins.push(...(0, _utils.getModulesPlugins)(options, this));
59
- } // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS
60
-
59
+ }
61
60
 
62
- const importPrefix = (0, _utils.getImportPrefix)(this, options.importLoaders);
63
- plugins.push((0, _plugins.icssParser)({
64
- loaderContext: this,
65
- importPrefix,
66
- localsConvention: options.localsConvention
67
- }));
61
+ const exportType = options.onlyLocals ? 'locals' : 'full';
62
+ plugins.push((0, _plugins.icssParser)());
68
63
 
69
- if (options.import !== false) {
64
+ if (options.import !== false && exportType === 'full') {
70
65
  plugins.push((0, _plugins.importParser)({
71
- loaderContext: this,
72
- importPrefix,
73
66
  filter: (0, _utils.getFilter)(options.import, this.resourcePath)
74
67
  }));
75
68
  }
76
69
 
77
- if (options.url !== false) {
70
+ if (options.url !== false && exportType === 'full') {
78
71
  plugins.push((0, _plugins.urlParser)({
79
- loaderContext: this,
80
72
  filter: (0, _utils.getFilter)(options.url, this.resourcePath, value => (0, _loaderUtils.isUrlRequest)(value))
81
73
  }));
82
74
  }
@@ -88,36 +80,42 @@ function loader(content, map, meta) {
88
80
  prev: map,
89
81
  inline: false,
90
82
  annotation: false
91
- } : null
83
+ } : false
92
84
  }).then(result => {
93
85
  result.warnings().forEach(warning => this.emitWarning(new _Warning.default(warning)));
94
-
95
- if (!result.messages) {
96
- // eslint-disable-next-line no-param-reassign
97
- result.messages = [];
98
- }
99
-
100
- const {
101
- onlyLocals
102
- } = options;
103
- const importItems = result.messages.filter(message => message.type === 'import' ? message : false).reduce((accumulator, currentValue) => {
104
- accumulator.push(currentValue.import);
105
- return accumulator;
106
- }, []);
107
- const exportItems = result.messages.filter(message => message.type === 'export' ? message : false).reduce((accumulator, currentValue) => {
108
- accumulator.push(currentValue.export);
109
- return accumulator;
110
- }, []);
111
- const importCode = (0, _utils.getImportCode)(importItems, onlyLocals);
112
- const moduleCode = (0, _utils.getModuleCode)(result, sourceMap, onlyLocals);
113
- const exportCode = (0, _utils.getExportCode)(exportItems, onlyLocals);
114
- const apiCode = (0, _utils.getApiCode)(this, sourceMap, onlyLocals);
115
- return callback(null, (0, _utils.prepareCode)({
116
- apiCode,
117
- importCode,
118
- moduleCode,
119
- exportCode
120
- }, result.messages, this, importPrefix, onlyLocals));
86
+ const imports = [];
87
+ const exports = [];
88
+ const replacers = [];
89
+
90
+ for (const message of result.messages) {
91
+ // eslint-disable-next-line default-case
92
+ switch (message.type) {
93
+ case 'import':
94
+ imports.push(message.value);
95
+ break;
96
+
97
+ case 'export':
98
+ exports.push(message.value);
99
+ break;
100
+
101
+ case 'replacer':
102
+ replacers.push(message.value);
103
+ break;
104
+ }
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(''));
121
119
  }).catch(error => {
122
120
  callback(error.name === 'CssSyntaxError' ? new _CssSyntaxError.default(error) : error);
123
121
  });
package/dist/options.json CHANGED
@@ -30,14 +30,14 @@
30
30
  "type": "boolean"
31
31
  },
32
32
  {
33
- "enum": ["local", "global"]
33
+ "enum": ["local", "global", "pure"]
34
34
  },
35
35
  {
36
36
  "type": "object",
37
37
  "additionalProperties": false,
38
38
  "properties": {
39
39
  "mode": {
40
- "enum": ["local", "global"]
40
+ "enum": ["local", "global", "pure"]
41
41
  },
42
42
  "localIdentName": {
43
43
  "type": "string"
@@ -9,79 +9,65 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _icssUtils = require("icss-utils");
11
11
 
12
- var _loaderUtils = _interopRequireDefault(require("loader-utils"));
13
-
14
- var _utils = require("../utils");
15
-
16
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
13
 
18
14
  const pluginName = 'postcss-icss-parser';
19
15
 
20
- function hasImportMessage(messages, url) {
21
- return messages.find(message => message.pluginName === pluginName && message.type === 'import' && message.item.url === url && message.item.media === '');
22
- }
23
-
24
- var _default = _postcss.default.plugin(pluginName, (options = {}) => function process(css, result) {
16
+ var _default = _postcss.default.plugin(pluginName, () => function process(css, result) {
25
17
  const importReplacements = Object.create(null);
26
18
  const {
27
19
  icssImports,
28
20
  icssExports
29
21
  } = (0, _icssUtils.extractICSS)(css);
30
- let index = 0;
22
+ Object.keys(icssImports).forEach((url, importIndex) => {
23
+ const tokens = Object.keys(icssImports[url]);
31
24
 
32
- for (const importUrl of Object.keys(icssImports)) {
33
- const url = _loaderUtils.default.parseString(importUrl);
25
+ if (tokens.length === 0) {
26
+ return;
27
+ }
34
28
 
35
- for (const token of Object.keys(icssImports[importUrl])) {
36
- index += 1;
37
- importReplacements[token] = `___CSS_LOADER_IMPORT___${index}___`;
29
+ const importName = `___CSS_LOADER_ICSS_IMPORT_${importIndex}___`;
30
+ result.messages.push({
31
+ pluginName,
32
+ type: 'import',
33
+ value: {
34
+ type: 'icss-import',
35
+ name: importName,
36
+ url
37
+ }
38
+ });
39
+ tokens.forEach((token, replacementIndex) => {
40
+ const name = `___CSS_LOADER_ICSS_IMPORT_${importIndex}_REPLACEMENT_${replacementIndex}___`;
41
+ const localName = icssImports[url][token];
42
+ importReplacements[token] = name;
38
43
  result.messages.push({
39
44
  pluginName,
40
- type: 'icss-import',
41
- item: {
42
- url,
43
- export: icssImports[importUrl][token],
44
- index
45
+ type: 'replacer',
46
+ value: {
47
+ type: 'icss-import',
48
+ name,
49
+ importName,
50
+ localName
45
51
  }
46
52
  });
53
+ });
54
+ });
47
55
 
48
- if (!hasImportMessage(result.messages, url)) {
49
- const media = '';
50
- const {
51
- loaderContext,
52
- importPrefix
53
- } = options;
54
- result.messages.push({
55
- pluginName,
56
- type: 'import',
57
- import: (0, _utils.getImportItemCode)({
58
- url,
59
- media
60
- }, loaderContext, importPrefix),
61
- item: {
62
- url,
63
- media
64
- }
65
- });
66
- }
67
- }
56
+ if (Object.keys(importReplacements).length > 0) {
57
+ (0, _icssUtils.replaceSymbols)(css, importReplacements);
68
58
  }
69
59
 
70
- (0, _icssUtils.replaceSymbols)(css, importReplacements);
71
-
72
- for (const exportName of Object.keys(icssExports)) {
73
- const name = exportName;
60
+ Object.keys(icssExports).forEach(name => {
74
61
  const value = (0, _icssUtils.replaceValueSymbols)(icssExports[name], importReplacements);
75
62
  result.messages.push({
76
63
  pluginName,
77
- export: (0, _utils.getExportItemCode)(name, value, options.localsConvention),
78
64
  type: 'export',
79
- item: {
65
+ value: {
80
66
  name,
81
67
  value
82
68
  }
83
69
  });
84
- }
70
+ });
85
71
  });
86
72
 
87
73
  exports.default = _default;
@@ -9,8 +9,6 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
11
 
12
- var _utils = require("../utils");
13
-
14
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
13
 
16
14
  const pluginName = 'postcss-import-parser';
@@ -53,7 +51,7 @@ function parseImport(params) {
53
51
  }
54
52
 
55
53
  function walkAtRules(css, result, filter) {
56
- const items = [];
54
+ const items = new Map();
57
55
  css.walkAtRules(/^import$/i, atRule => {
58
56
  // Convert only top-level @import
59
57
  if (atRule.parent.type !== 'root') {
@@ -85,22 +83,43 @@ function walkAtRules(css, result, filter) {
85
83
  url,
86
84
  media
87
85
  } = parsed;
88
- items.push({
89
- url,
90
- media
91
- });
86
+ const value = items.get(url);
87
+
88
+ if (!value) {
89
+ items.set(url, new Set([media]));
90
+ } else {
91
+ value.add(media);
92
+ }
92
93
  });
93
94
  return items;
94
95
  }
95
96
 
96
- var _default = _postcss.default.plugin(pluginName, (options = {}) => function process(css, result) {
97
- const traversed = walkAtRules(css, result, options.filter);
98
- const paths = (0, _utils.uniqWith)(traversed, (value, other) => value.url === other.url && value.media === other.media);
99
- paths.forEach(item => {
97
+ var _default = _postcss.default.plugin(pluginName, options => function process(css, result) {
98
+ 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) => {
109
+ const {
110
+ url,
111
+ media
112
+ } = item;
113
+ const name = `___CSS_LOADER_AT_RULE_IMPORT_${index}___`;
100
114
  result.messages.push({
101
115
  pluginName,
102
116
  type: 'import',
103
- import: (0, _utils.getImportItemCode)(item, options.loaderContext, options.importPrefix)
117
+ value: {
118
+ type: '@import',
119
+ name,
120
+ url,
121
+ media
122
+ }
104
123
  });
105
124
  });
106
125
  });
@@ -9,8 +9,6 @@ var _postcss = _interopRequireDefault(require("postcss"));
9
9
 
10
10
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
11
 
12
- var _utils = require("../utils");
13
-
14
12
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
13
 
16
14
  const pluginName = 'postcss-url-parser';
@@ -56,7 +54,7 @@ function walkUrls(parsed, callback) {
56
54
  });
57
55
  }
58
56
 
59
- function getUrlsFromValue(value, result, filter, decl = null) {
57
+ function getUrlsFromValue(value, result, filter, decl) {
60
58
  if (!needParseDecl.test(value)) {
61
59
  return;
62
60
  }
@@ -65,9 +63,9 @@ function getUrlsFromValue(value, result, filter, decl = null) {
65
63
  const urls = [];
66
64
  walkUrls(parsed, (node, url, needQuotes) => {
67
65
  if (url.trim().replace(/\\[\r\n]/g, '').length === 0) {
68
- result.warn(`Unable to find uri in '${decl ? decl.toString() : value}'`, decl ? {
66
+ result.warn(`Unable to find uri in '${decl ? decl.toString() : value}'`, {
69
67
  node: decl
70
- } : {});
68
+ });
71
69
  return;
72
70
  }
73
71
 
@@ -75,8 +73,12 @@ function getUrlsFromValue(value, result, filter, decl = null) {
75
73
  return;
76
74
  }
77
75
 
76
+ const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
77
+ const hash = singleQuery || hashValue ? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}` : '';
78
78
  urls.push({
79
- url,
79
+ node,
80
+ url: normalizedUrl,
81
+ hash,
80
82
  needQuotes
81
83
  });
82
84
  }); // eslint-disable-next-line consistent-return
@@ -87,16 +89,12 @@ function getUrlsFromValue(value, result, filter, decl = null) {
87
89
  };
88
90
  }
89
91
 
90
- function walkDeclsWithUrl(css, result, filter) {
92
+ function walkDecls(css, result, filter) {
91
93
  const items = [];
92
94
  css.walkDecls(decl => {
93
95
  const item = getUrlsFromValue(decl.value, result, filter, decl);
94
96
 
95
- if (!item) {
96
- return;
97
- }
98
-
99
- if (item.urls.length === 0) {
97
+ if (!item || item.urls.length === 0) {
100
98
  return;
101
99
  }
102
100
 
@@ -109,67 +107,82 @@ function walkDeclsWithUrl(css, result, filter) {
109
107
  return items;
110
108
  }
111
109
 
112
- var _default = _postcss.default.plugin(pluginName, (options = {}) => function process(css, result) {
113
- const traversed = walkDeclsWithUrl(css, result, options.filter);
114
- const paths = (0, _utils.uniqWith)((0, _utils.flatten)(traversed.map(item => item.urls)), (value, other) => value.url === other.url && value.needQuotes === other.needQuotes);
110
+ function flatten(array) {
111
+ return array.reduce((a, b) => a.concat(b), []);
112
+ }
115
113
 
116
- if (paths.length === 0) {
117
- return;
118
- }
114
+ function collectUniqueUrlsWithNodes(array) {
115
+ return array.reduce((accumulator, currentValue) => {
116
+ const {
117
+ url,
118
+ needQuotes,
119
+ hash,
120
+ node
121
+ } = currentValue;
122
+ const found = accumulator.find(item => url === item.url && needQuotes === item.needQuotes && hash === item.hash);
123
+
124
+ if (!found) {
125
+ accumulator.push({
126
+ url,
127
+ hash,
128
+ needQuotes,
129
+ nodes: [node]
130
+ });
131
+ } else {
132
+ found.nodes.push(node);
133
+ }
134
+
135
+ return accumulator;
136
+ }, []);
137
+ }
119
138
 
120
- const placeholders = [];
121
- let hasUrlHelper = false;
139
+ var _default = _postcss.default.plugin(pluginName, options => function process(css, result) {
140
+ const traversed = walkDecls(css, result, options.filter);
141
+ const paths = collectUniqueUrlsWithNodes(flatten(traversed.map(item => item.urls)));
142
+ const replacers = new Map();
122
143
  paths.forEach((path, index) => {
123
- const {
124
- loaderContext
125
- } = options;
126
- const placeholder = `___CSS_LOADER_URL___${index}___`;
127
144
  const {
128
145
  url,
129
- needQuotes
146
+ hash,
147
+ needQuotes,
148
+ nodes
130
149
  } = path;
131
- placeholders.push({
132
- placeholder,
133
- path
134
- });
135
-
136
- if (!hasUrlHelper) {
137
- result.messages.push({
138
- pluginName,
139
- type: 'import',
140
- import: (0, _utils.getUrlHelperCode)(loaderContext)
141
- }); // eslint-disable-next-line no-param-reassign
142
-
143
- hasUrlHelper = true;
144
- }
145
-
150
+ const name = `___CSS_LOADER_URL_IMPORT_${index}___`;
146
151
  result.messages.push({
147
152
  pluginName,
148
153
  type: 'import',
149
- import: (0, _utils.getUrlItemCode)({
154
+ value: {
155
+ type: 'url',
156
+ name,
150
157
  url,
151
- placeholder,
152
- needQuotes
153
- }, loaderContext),
154
- importType: 'url',
155
- placeholder
158
+ needQuotes,
159
+ hash,
160
+ index
161
+ }
162
+ }, {
163
+ pluginName,
164
+ type: 'replacer',
165
+ value: {
166
+ type: 'url',
167
+ name
168
+ }
169
+ });
170
+ nodes.forEach(node => {
171
+ replacers.set(node, name);
156
172
  });
157
173
  });
158
174
  traversed.forEach(item => {
159
- walkUrls(item.parsed, (node, url, needQuotes) => {
160
- const value = placeholders.find(placeholder => placeholder.path.url === url && placeholder.path.needQuotes === needQuotes);
175
+ walkUrls(item.parsed, node => {
176
+ const name = replacers.get(node);
161
177
 
162
- if (!value) {
178
+ if (!name) {
163
179
  return;
164
- }
180
+ } // eslint-disable-next-line no-param-reassign
165
181
 
166
- const {
167
- placeholder
168
- } = value; // eslint-disable-next-line no-param-reassign
169
182
 
170
183
  node.type = 'word'; // eslint-disable-next-line no-param-reassign
171
184
 
172
- node.value = placeholder;
185
+ node.value = name;
173
186
  }); // eslint-disable-next-line no-param-reassign
174
187
 
175
188
  item.decl.value = item.parsed.toString();
@@ -7,7 +7,7 @@ module.exports = function (url, options) {
7
7
  } // eslint-disable-next-line no-underscore-dangle, no-param-reassign
8
8
 
9
9
 
10
- url = url.__esModule ? url.default : url;
10
+ url = url && url.__esModule ? url.default : url;
11
11
 
12
12
  if (typeof url !== 'string') {
13
13
  return url;
package/dist/utils.js CHANGED
@@ -3,23 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.uniqWith = uniqWith;
7
- exports.flatten = flatten;
8
- exports.dashesCamelCase = dashesCamelCase;
9
- exports.getImportPrefix = getImportPrefix;
10
- exports.getLocalIdent = getLocalIdent;
11
6
  exports.getFilter = getFilter;
12
7
  exports.getModulesPlugins = getModulesPlugins;
13
8
  exports.normalizeSourceMap = normalizeSourceMap;
14
- exports.getImportItemCode = getImportItemCode;
15
- exports.getUrlHelperCode = getUrlHelperCode;
16
- exports.getUrlItemCode = getUrlItemCode;
17
9
  exports.getApiCode = getApiCode;
18
10
  exports.getImportCode = getImportCode;
19
11
  exports.getModuleCode = getModuleCode;
20
- exports.getExportItemCode = getExportItemCode;
21
12
  exports.getExportCode = getExportCode;
22
- exports.prepareCode = prepareCode;
23
13
 
24
14
  var _path = _interopRequireDefault(require("path"));
25
15
 
@@ -49,18 +39,6 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
49
39
  MIT License http://www.opensource.org/licenses/mit-license.php
50
40
  Author Tobias Koppers @sokra
51
41
  */
52
- function uniqWith(array, comparator) {
53
- return array.reduce((acc, d) => !acc.some(item => comparator(d, item)) ? [...acc, d] : acc, []);
54
- }
55
-
56
- function flatten(array) {
57
- return array.reduce((a, b) => a.concat(b), []);
58
- }
59
-
60
- function dashesCamelCase(str) {
61
- return str.replace(/-+(\w)/g, (match, firstLetter) => firstLetter.toUpperCase());
62
- }
63
-
64
42
  function getImportPrefix(loaderContext, importLoaders) {
65
43
  if (importLoaders === false) {
66
44
  return '';
@@ -190,169 +168,170 @@ function normalizeSourceMap(map) {
190
168
  return newMap;
191
169
  }
192
170
 
193
- function getImportItemCode(item, loaderContext, importPrefix) {
194
- const {
195
- url
196
- } = item;
197
- const media = item.media || '';
198
-
199
- if (!(0, _loaderUtils.isUrlRequest)(url)) {
200
- return `exports.push([module.id, ${JSON.stringify(`@import url(${url});`)}, ${JSON.stringify(media)}]);`;
201
- }
202
-
203
- const importUrl = importPrefix + (0, _loaderUtils.urlToRequest)(url);
204
- return `exports.i(require(${(0, _loaderUtils.stringifyRequest)(loaderContext, importUrl)}), ${JSON.stringify(media)});`;
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`;
205
174
  }
206
175
 
207
- function getUrlHelperCode(loaderContext) {
208
- return `var getUrl = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/getUrl.js'))});`;
209
- }
210
-
211
- function getUrlItemCode(item, loaderContext) {
212
- const {
213
- url,
214
- placeholder,
215
- needQuotes
216
- } = item; // Remove `#hash` and `?#hash` from `require`
217
-
218
- const [normalizedUrl, singleQuery, hashValue] = url.split(/(\?)?#/);
219
- const hash = singleQuery || hashValue ? `"${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}"` : '';
220
- const options = [];
221
-
222
- if (hash) {
223
- options.push(`hash: ${hash}`);
224
- }
225
-
226
- if (needQuotes) {
227
- options.push(`needQuotes: true`);
228
- }
229
-
230
- const preparedOptions = options.length > 0 ? `, { ${options.join(', ')} }` : '';
231
- return `var ${placeholder} = getUrl(require(${(0, _loaderUtils.stringifyRequest)(loaderContext, (0, _loaderUtils.urlToRequest)(normalizedUrl))})${preparedOptions});`;
232
- }
233
-
234
- function getApiCode(loaderContext, sourceMap, onlyLocals) {
235
- if (onlyLocals) {
236
- return '';
237
- }
238
-
239
- return `exports = module.exports = require(${(0, _loaderUtils.stringifyRequest)(loaderContext, require.resolve('./runtime/api'))})(${sourceMap});\n`;
240
- }
241
-
242
- function getImportCode(importItems, onlyLocals) {
243
- if (importItems.length === 0 || onlyLocals) {
244
- return '';
245
- }
246
-
247
- return `// Imports\n${importItems.join('\n')}\n`;
248
- }
249
-
250
- function getModuleCode(result, sourceMap, onlyLocals) {
251
- if (onlyLocals) {
252
- return '';
253
- }
254
-
255
- return `// Module\nexports.push([module.id, ${JSON.stringify(result.css)}, ""${sourceMap && result.map ? `,${result.map}` : ''}]);\n`;
256
- }
257
-
258
- function getExportItemCode(key, value, localsConvention) {
259
- let targetKey;
260
- const items = [];
261
-
262
- function addEntry(k) {
263
- items.push(`\t${JSON.stringify(k)}: ${JSON.stringify(value)}`);
264
- }
265
-
266
- switch (localsConvention) {
267
- case 'camelCase':
268
- addEntry(key);
269
- targetKey = (0, _camelcase.default)(key);
270
-
271
- if (targetKey !== key) {
272
- addEntry(targetKey);
176
+ function getImportCode(loaderContext, imports, options) {
177
+ const importItems = [];
178
+ const codeItems = [];
179
+ const urlImportNames = new Map();
180
+ let hasUrlHelperCode = false;
181
+ let importPrefix;
182
+ imports.forEach(item => {
183
+ if (item.type === '@import' || item.type === 'icss-import') {
184
+ const media = item.media ? `, ${JSON.stringify(item.media)}` : '';
185
+
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;
273
190
  }
274
191
 
275
- break;
276
-
277
- case 'camelCaseOnly':
278
- addEntry((0, _camelcase.default)(key));
279
- break;
192
+ if (!importPrefix) {
193
+ importPrefix = getImportPrefix(loaderContext, options.importLoaders);
194
+ }
280
195
 
281
- case 'dashes':
282
- addEntry(key);
283
- targetKey = dashesCamelCase(key);
196
+ const url = (0, _loaderUtils.stringifyRequest)(loaderContext, importPrefix + (0, _loaderUtils.urlToRequest)(item.url));
197
+ importItems.push(`var ${item.name} = require(${url});`);
284
198
 
285
- if (targetKey !== key) {
286
- addEntry(targetKey);
199
+ if (options.exportType === 'full') {
200
+ codeItems.push(`exports.i(${item.name}${media});`);
287
201
  }
202
+ }
288
203
 
289
- break;
204
+ if (item.type === 'url') {
205
+ if (!hasUrlHelperCode) {
206
+ const pathToGetUrl = require.resolve('./runtime/getUrl.js');
290
207
 
291
- case 'dashesOnly':
292
- addEntry(dashesCamelCase(key));
293
- break;
208
+ const url = (0, _loaderUtils.stringifyRequest)(loaderContext, pathToGetUrl);
209
+ importItems.push(`var ___CSS_LOADER_GET_URL_IMPORT___ = require(${url});`);
210
+ hasUrlHelperCode = true;
211
+ }
294
212
 
295
- case 'asIs':
296
- default:
297
- addEntry(key);
298
- break;
299
- }
213
+ const {
214
+ name,
215
+ url,
216
+ hash,
217
+ needQuotes,
218
+ index
219
+ } = item;
220
+ let importName = urlImportNames.get(url);
221
+
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
+ }
300
228
 
301
- return items.join(',\n');
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});`);
232
+ }
233
+ });
234
+ return `// Imports\n${importItems.join('\n')}\n${codeItems.join('\n')}\n`;
302
235
  }
303
236
 
304
- function getExportCode(exportItems, onlyLocals) {
305
- if (exportItems.length === 0) {
306
- return '';
307
- }
237
+ function getModuleCode(loaderContext, result, replacers, sourceMap) {
238
+ const {
239
+ css,
240
+ map
241
+ } = result;
242
+ const sourceMapValue = sourceMap && map ? `,${map}` : '';
243
+ let cssCode = JSON.stringify(css);
244
+ replacers.forEach(replacer => {
245
+ const {
246
+ type,
247
+ name
248
+ } = replacer;
249
+
250
+ if (type === 'url') {
251
+ cssCode = cssCode.replace(new RegExp(name, 'g'), () => `" + ${name} + "`);
252
+ }
308
253
 
309
- return `// Exports\n${onlyLocals ? 'module.exports' : 'exports.locals'} = {\n${exportItems.join(',\n')}\n};`;
254
+ if (type === 'icss-import') {
255
+ const {
256
+ importName,
257
+ localName
258
+ } = replacer;
259
+ cssCode = cssCode.replace(new RegExp(name, 'g'), () => `" + ${importName}.locals[${JSON.stringify(localName)}] + "`);
260
+ }
261
+ });
262
+ return `// Module\nexports.push([module.id, ${cssCode}, ""${sourceMapValue}]);\n`;
310
263
  }
311
264
 
312
- function getIcssReplacer(item, loaderContext, importPrefix, onlyLocals) {
313
- const importUrl = importPrefix + (0, _loaderUtils.urlToRequest)(item.url);
314
- return () => onlyLocals ? `" + require(${(0, _loaderUtils.stringifyRequest)(loaderContext, importUrl)})[${JSON.stringify(item.export)}] + "` : `" + require(${(0, _loaderUtils.stringifyRequest)(loaderContext, importUrl)}).locals[${JSON.stringify(item.export)}] + "`;
265
+ function dashesCamelCase(str) {
266
+ return str.replace(/-+(\w)/g, (match, firstLetter) => firstLetter.toUpperCase());
315
267
  }
316
268
 
317
- function prepareCode(file, messages, loaderContext, importPrefix, onlyLocals) {
318
- const {
319
- apiCode,
320
- importCode
321
- } = file;
322
- let {
323
- moduleCode,
324
- exportCode
325
- } = file;
326
- messages.filter(message => message.type === 'icss-import' || message.type === 'import' && message.importType === 'url').forEach(message => {
327
- // Replace all urls on `require`
328
- if (message.type === 'import') {
329
- const {
330
- placeholder
331
- } = message;
332
-
333
- if (moduleCode) {
334
- // eslint-disable-next-line no-param-reassign
335
- moduleCode = moduleCode.replace(new RegExp(placeholder, 'g'), () => `" + ${placeholder} + "`);
336
- }
337
- } // Replace external ICSS import on `require`
269
+ function getExportCode(loaderContext, exports, replacers, options) {
270
+ const items = [];
338
271
 
272
+ function addExportedItem(name, value) {
273
+ items.push(`\t${JSON.stringify(name)}: ${JSON.stringify(value)}`);
274
+ }
339
275
 
340
- if (message.type === 'icss-import') {
276
+ exports.forEach(item => {
277
+ const {
278
+ name,
279
+ value
280
+ } = item;
281
+
282
+ switch (options.localsConvention) {
283
+ case 'camelCase':
284
+ {
285
+ addExportedItem(name, value);
286
+ const modifiedName = (0, _camelcase.default)(name);
287
+
288
+ if (modifiedName !== name) {
289
+ addExportedItem(modifiedName, value);
290
+ }
291
+
292
+ break;
293
+ }
294
+
295
+ case 'camelCaseOnly':
296
+ {
297
+ addExportedItem((0, _camelcase.default)(name), value);
298
+ break;
299
+ }
300
+
301
+ case 'dashes':
302
+ {
303
+ addExportedItem(name, value);
304
+ const modifiedName = dashesCamelCase(name);
305
+
306
+ if (modifiedName !== name) {
307
+ addExportedItem(modifiedName, value);
308
+ }
309
+
310
+ break;
311
+ }
312
+
313
+ case 'dashesOnly':
314
+ {
315
+ addExportedItem(dashesCamelCase(name), value);
316
+ break;
317
+ }
318
+
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') {
341
328
  const {
342
- item
343
- } = message;
344
- const replacer = getIcssReplacer(item, loaderContext, importPrefix, onlyLocals);
345
-
346
- if (moduleCode) {
347
- // eslint-disable-next-line no-param-reassign
348
- moduleCode = moduleCode.replace(new RegExp(`___CSS_LOADER_IMPORT___(${item.index})___`, 'g'), replacer);
349
- }
350
-
351
- if (exportCode) {
352
- // eslint-disable-next-line no-param-reassign
353
- exportCode = exportCode.replace(new RegExp(`___CSS_LOADER_IMPORT___(${item.index})___`, 'g'), replacer);
354
- }
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}] + "`);
355
334
  }
356
335
  });
357
- return [apiCode, importCode, moduleCode, exportCode].filter(Boolean).join('');
336
+ return exportCode;
358
337
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "css-loader",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "css loader module for webpack",
5
5
  "license": "MIT",
6
6
  "repository": "webpack-contrib/css-loader",