css-loader 3.6.0 → 4.2.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.
@@ -5,20 +5,20 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
+ var _util = require("util");
9
+
8
10
  var _postcss = _interopRequireDefault(require("postcss"));
9
11
 
10
12
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
11
13
 
12
- var _loaderUtils = require("loader-utils");
13
-
14
14
  var _utils = require("../utils");
15
15
 
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
 
18
18
  const pluginName = 'postcss-import-parser';
19
19
 
20
- var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
21
- const importsMap = new Map();
20
+ function walkAtRules(css, result, options, callback) {
21
+ const accumulator = [];
22
22
  css.walkAtRules(/^import$/i, atRule => {
23
23
  // Convert only top-level @import
24
24
  if (atRule.parent.type !== 'root') {
@@ -34,11 +34,11 @@ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
34
34
  }
35
35
 
36
36
  const {
37
- nodes
37
+ nodes: paramsNodes
38
38
  } = (0, _postcssValueParser.default)(atRule.params); // No nodes - `@import ;`
39
39
  // Invalid type - `@import foo-bar;`
40
40
 
41
- if (nodes.length === 0 || nodes[0].type !== 'string' && nodes[0].type !== 'function') {
41
+ if (paramsNodes.length === 0 || paramsNodes[0].type !== 'string' && paramsNodes[0].type !== 'function') {
42
42
  result.warn(`Unable to find uri in "${atRule.toString()}"`, {
43
43
  node: atRule
44
44
  });
@@ -48,20 +48,20 @@ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
48
48
  let isStringValue;
49
49
  let url;
50
50
 
51
- if (nodes[0].type === 'string') {
51
+ if (paramsNodes[0].type === 'string') {
52
52
  isStringValue = true;
53
- url = nodes[0].value;
54
- } else if (nodes[0].type === 'function') {
53
+ url = paramsNodes[0].value;
54
+ } else {
55
55
  // Invalid function - `@import nourl(test.css);`
56
- if (nodes[0].value.toLowerCase() !== 'url') {
56
+ if (paramsNodes[0].value.toLowerCase() !== 'url') {
57
57
  result.warn(`Unable to find uri in "${atRule.toString()}"`, {
58
58
  node: atRule
59
59
  });
60
60
  return;
61
61
  }
62
62
 
63
- isStringValue = nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
64
- url = isStringValue ? nodes[0].nodes[0].value : _postcssValueParser.default.stringify(nodes[0].nodes);
63
+ isStringValue = paramsNodes[0].nodes.length !== 0 && paramsNodes[0].nodes[0].type === 'string';
64
+ url = isStringValue ? paramsNodes[0].nodes[0].value : _postcssValueParser.default.stringify(paramsNodes[0].nodes);
65
65
  } // Empty url - `@import "";` or `@import url();`
66
66
 
67
67
 
@@ -72,70 +72,143 @@ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
72
72
  return;
73
73
  }
74
74
 
75
- const isRequestable = (0, _loaderUtils.isUrlRequest)(url);
75
+ accumulator.push({
76
+ atRule,
77
+ url,
78
+ isStringValue,
79
+ mediaNodes: paramsNodes.slice(1)
80
+ });
81
+ });
82
+ callback(null, accumulator);
83
+ }
84
+
85
+ const asyncWalkAtRules = (0, _util.promisify)(walkAtRules);
86
+
87
+ var _default = _postcss.default.plugin(pluginName, options => async (css, result) => {
88
+ const parsedResults = await asyncWalkAtRules(css, result, options);
89
+
90
+ if (parsedResults.length === 0) {
91
+ return Promise.resolve();
92
+ }
93
+
94
+ const imports = new Map();
95
+ const tasks = [];
96
+
97
+ for (const parsedResult of parsedResults) {
98
+ const {
99
+ atRule,
100
+ url,
101
+ isStringValue,
102
+ mediaNodes
103
+ } = parsedResult;
104
+ let normalizedUrl = url;
105
+ let prefix = '';
106
+ const isRequestable = (0, _utils.isUrlRequestable)(normalizedUrl);
76
107
 
77
108
  if (isRequestable) {
78
- url = (0, _utils.normalizeUrl)(url, isStringValue); // Empty url after normalize - `@import '\
109
+ const queryParts = normalizedUrl.split('!');
110
+
111
+ if (queryParts.length > 1) {
112
+ normalizedUrl = queryParts.pop();
113
+ prefix = queryParts.join('!');
114
+ }
115
+
116
+ normalizedUrl = (0, _utils.normalizeUrl)(normalizedUrl, isStringValue); // Empty url after normalize - `@import '\
79
117
  // \
80
118
  // \
81
119
  // ';
82
120
 
83
- if (url.trim().length === 0) {
121
+ if (normalizedUrl.trim().length === 0) {
84
122
  result.warn(`Unable to find uri in "${atRule.toString()}"`, {
85
123
  node: atRule
86
- });
87
- return;
124
+ }); // eslint-disable-next-line no-continue
125
+
126
+ continue;
88
127
  }
89
128
  }
90
129
 
91
- const media = _postcssValueParser.default.stringify(nodes.slice(1)).trim().toLowerCase();
130
+ let media;
92
131
 
93
- if (options.filter && !options.filter({
94
- url,
95
- media
96
- })) {
97
- return;
132
+ if (mediaNodes.length > 0) {
133
+ media = _postcssValueParser.default.stringify(mediaNodes).trim().toLowerCase();
134
+ }
135
+
136
+ if (options.filter && !options.filter(normalizedUrl, media)) {
137
+ // eslint-disable-next-line no-continue
138
+ continue;
98
139
  }
99
140
 
100
141
  atRule.remove();
101
142
 
102
143
  if (isRequestable) {
103
- const importKey = url;
104
- let importName = importsMap.get(importKey);
144
+ const request = (0, _utils.requestify)(normalizedUrl, options.rootContext);
145
+ tasks.push((async () => {
146
+ const {
147
+ resolver,
148
+ context
149
+ } = options;
150
+ const resolvedUrl = await (0, _utils.resolveRequests)(resolver, context, [...new Set([request, normalizedUrl])]);
151
+ return {
152
+ url: resolvedUrl,
153
+ media,
154
+ prefix,
155
+ isRequestable
156
+ };
157
+ })());
158
+ } else {
159
+ tasks.push({
160
+ url,
161
+ media,
162
+ prefix,
163
+ isRequestable
164
+ });
165
+ }
166
+ }
167
+
168
+ const results = await Promise.all(tasks);
169
+
170
+ for (let index = 0; index <= results.length - 1; index++) {
171
+ const {
172
+ url,
173
+ isRequestable,
174
+ media
175
+ } = results[index];
176
+
177
+ if (isRequestable) {
178
+ const {
179
+ prefix
180
+ } = results[index];
181
+ const newUrl = prefix ? `${prefix}!${url}` : url;
182
+ const importKey = newUrl;
183
+ let importName = imports.get(importKey);
105
184
 
106
185
  if (!importName) {
107
- importName = `___CSS_LOADER_AT_RULE_IMPORT_${importsMap.size}___`;
108
- importsMap.set(importKey, importName);
109
- result.messages.push({
110
- type: 'import',
111
- value: {
112
- importName,
113
- url: options.urlHandler ? options.urlHandler(url) : url
114
- }
186
+ importName = `___CSS_LOADER_AT_RULE_IMPORT_${imports.size}___`;
187
+ imports.set(importKey, importName);
188
+ options.imports.push({
189
+ importName,
190
+ url: options.urlHandler(newUrl),
191
+ index
115
192
  });
116
193
  }
117
194
 
118
- result.messages.push({
119
- type: 'api-import',
120
- value: {
121
- type: 'internal',
122
- importName,
123
- media
124
- }
125
- });
126
- return;
195
+ options.api.push({
196
+ importName,
197
+ media,
198
+ index
199
+ }); // eslint-disable-next-line no-continue
200
+
201
+ continue;
127
202
  }
128
203
 
129
- result.messages.push({
130
- pluginName,
131
- type: 'api-import',
132
- value: {
133
- type: 'external',
134
- url,
135
- media
136
- }
204
+ options.api.push({
205
+ url,
206
+ media,
207
+ index
137
208
  });
138
- });
209
+ }
210
+
211
+ return Promise.resolve();
139
212
  });
140
213
 
141
214
  exports.default = _default;
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
+ var _util = require("util");
9
+
8
10
  var _postcss = _interopRequireDefault(require("postcss"));
9
11
 
10
12
  var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
@@ -22,140 +24,234 @@ function getNodeFromUrlFunc(node) {
22
24
  return node.nodes && node.nodes[0];
23
25
  }
24
26
 
25
- function walkUrls(parsed, callback) {
26
- parsed.walk(node => {
27
- if (node.type !== 'function') {
27
+ function shouldHandleRule(rule, decl, result) {
28
+ // https://www.w3.org/TR/css-syntax-3/#typedef-url-token
29
+ if (rule.url.replace(/^[\s]+|[\s]+$/g, '').length === 0) {
30
+ result.warn(`Unable to find uri in '${decl.toString()}'`, {
31
+ node: decl
32
+ });
33
+ return false;
34
+ }
35
+
36
+ if (!(0, _utils.isUrlRequestable)(rule.url)) {
37
+ return false;
38
+ }
39
+
40
+ return true;
41
+ }
42
+
43
+ function walkCss(css, result, options, callback) {
44
+ const accumulator = [];
45
+ css.walkDecls(decl => {
46
+ if (!needParseDecl.test(decl.value)) {
28
47
  return;
29
48
  }
30
49
 
31
- if (isUrlFunc.test(node.value)) {
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`
38
- // eslint-disable-next-line consistent-return
39
-
40
- return false;
41
- }
50
+ const parsed = (0, _postcssValueParser.default)(decl.value);
51
+ parsed.walk(node => {
52
+ if (node.type !== 'function') {
53
+ return;
54
+ }
42
55
 
43
- if (isImageSetFunc.test(node.value)) {
44
- for (const nNode of node.nodes) {
56
+ if (isUrlFunc.test(node.value)) {
45
57
  const {
46
- type,
47
- value
48
- } = nNode;
58
+ nodes
59
+ } = node;
60
+ const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
61
+ const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
62
+ const rule = {
63
+ node: getNodeFromUrlFunc(node),
64
+ url,
65
+ needQuotes: false,
66
+ isStringValue
67
+ };
68
+
69
+ if (shouldHandleRule(rule, decl, result)) {
70
+ accumulator.push({
71
+ decl,
72
+ rule,
73
+ parsed
74
+ });
75
+ } // Do not traverse inside `url`
76
+ // eslint-disable-next-line consistent-return
49
77
 
50
- if (type === 'function' && isUrlFunc.test(value)) {
78
+
79
+ return false;
80
+ } else if (isImageSetFunc.test(node.value)) {
81
+ for (const nNode of node.nodes) {
51
82
  const {
52
- nodes
83
+ type,
84
+ value
53
85
  } = 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);
57
- }
58
86
 
59
- if (type === 'string') {
60
- callback(nNode, value, true, true);
61
- }
62
- } // Do not traverse inside `image-set`
63
- // eslint-disable-next-line consistent-return
87
+ if (type === 'function' && isUrlFunc.test(value)) {
88
+ const {
89
+ nodes
90
+ } = nNode;
91
+ const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
92
+ const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
93
+ const rule = {
94
+ node: getNodeFromUrlFunc(nNode),
95
+ url,
96
+ needQuotes: false,
97
+ isStringValue
98
+ };
64
99
 
100
+ if (shouldHandleRule(rule, decl, result)) {
101
+ accumulator.push({
102
+ decl,
103
+ rule,
104
+ parsed
105
+ });
106
+ }
107
+ } else if (type === 'string') {
108
+ const rule = {
109
+ node: nNode,
110
+ url: value,
111
+ needQuotes: true,
112
+ isStringValue: true
113
+ };
65
114
 
66
- return false;
67
- }
115
+ if (shouldHandleRule(rule, decl, result)) {
116
+ accumulator.push({
117
+ decl,
118
+ rule,
119
+ parsed
120
+ });
121
+ }
122
+ }
123
+ } // Do not traverse inside `image-set`
124
+ // eslint-disable-next-line consistent-return
125
+
126
+
127
+ return false;
128
+ }
129
+ });
68
130
  });
131
+ callback(null, accumulator);
69
132
  }
70
133
 
71
- var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
72
- const importsMap = new Map();
73
- const replacementsMap = new Map();
74
- let hasHelper = false;
75
- css.walkDecls(decl => {
76
- if (!needParseDecl.test(decl.value)) {
77
- return;
134
+ const asyncWalkCss = (0, _util.promisify)(walkCss);
135
+
136
+ var _default = _postcss.default.plugin(pluginName, options => async (css, result) => {
137
+ const parsedResults = await asyncWalkCss(css, result, options);
138
+
139
+ if (parsedResults.length === 0) {
140
+ return Promise.resolve();
141
+ }
142
+
143
+ const tasks = [];
144
+ const imports = new Map();
145
+ const replacements = new Map();
146
+ let hasUrlImportHelper = false;
147
+
148
+ for (const parsedResult of parsedResults) {
149
+ const {
150
+ url,
151
+ isStringValue
152
+ } = parsedResult.rule;
153
+ let normalizedUrl = url;
154
+ let prefix = '';
155
+ const queryParts = normalizedUrl.split('!');
156
+
157
+ if (queryParts.length > 1) {
158
+ normalizedUrl = queryParts.pop();
159
+ prefix = queryParts.join('!');
78
160
  }
79
161
 
80
- const parsed = (0, _postcssValueParser.default)(decl.value);
81
- walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
82
- // https://www.w3.org/TR/css-syntax-3/#typedef-url-token
83
- if (url.replace(/^[\s]+|[\s]+$/g, '').length === 0) {
84
- result.warn(`Unable to find uri in '${decl ? decl.toString() : decl.value}'`, {
85
- node: decl
86
- });
87
- return;
88
- }
162
+ normalizedUrl = (0, _utils.normalizeUrl)(normalizedUrl, isStringValue);
89
163
 
90
- if (options.filter && !options.filter(url)) {
91
- return;
92
- }
164
+ if (!options.filter(normalizedUrl)) {
165
+ // eslint-disable-next-line no-continue
166
+ continue;
167
+ }
93
168
 
94
- const splittedUrl = url.split(/(\?)?#/);
95
- const [urlWithoutHash, singleQuery, hashValue] = splittedUrl;
96
- const hash = singleQuery || hashValue ? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}` : '';
97
- const normalizedUrl = (0, _utils.normalizeUrl)(urlWithoutHash, isStringValue);
98
- const importKey = normalizedUrl;
99
- let importName = importsMap.get(importKey);
100
-
101
- if (!importName) {
102
- importName = `___CSS_LOADER_URL_IMPORT_${importsMap.size}___`;
103
- importsMap.set(importKey, importName);
104
-
105
- if (!hasHelper) {
106
- const urlToHelper = require.resolve('../runtime/getUrl.js');
107
-
108
- result.messages.push({
109
- pluginName,
110
- type: 'import',
111
- value: {
112
- importName: '___CSS_LOADER_GET_URL_IMPORT___',
113
- url: options.urlHandler ? options.urlHandler(urlToHelper) : urlToHelper
114
- }
115
- });
116
- hasHelper = true;
117
- }
118
-
119
- result.messages.push({
120
- pluginName,
121
- type: 'import',
122
- value: {
123
- importName,
124
- url: options.urlHandler ? options.urlHandler(normalizedUrl) : normalizedUrl
125
- }
126
- });
169
+ if (!hasUrlImportHelper) {
170
+ options.imports.push({
171
+ importName: '___CSS_LOADER_GET_URL_IMPORT___',
172
+ url: options.urlHandler(require.resolve('../runtime/getUrl.js')),
173
+ index: -1
174
+ });
175
+ hasUrlImportHelper = true;
176
+ }
177
+
178
+ const splittedUrl = normalizedUrl.split(/(\?)?#/);
179
+ const [pathname, query, hashOrQuery] = splittedUrl;
180
+ let hash = query ? '?' : '';
181
+ hash += hashOrQuery ? `#${hashOrQuery}` : '';
182
+ const request = (0, _utils.requestify)(pathname, options.rootContext);
183
+ tasks.push((async () => {
184
+ const {
185
+ resolver,
186
+ context
187
+ } = options;
188
+ const resolvedUrl = await (0, _utils.resolveRequests)(resolver, context, [...new Set([request, normalizedUrl])]);
189
+ return {
190
+ url: resolvedUrl,
191
+ prefix,
192
+ hash,
193
+ parsedResult
194
+ };
195
+ })());
196
+ }
197
+
198
+ const results = await Promise.all(tasks);
199
+
200
+ for (let index = 0; index <= results.length - 1; index++) {
201
+ const {
202
+ url,
203
+ prefix,
204
+ hash,
205
+ parsedResult: {
206
+ decl,
207
+ rule,
208
+ parsed
127
209
  }
210
+ } = results[index];
211
+ const newUrl = prefix ? `${prefix}!${url}` : url;
212
+ const importKey = newUrl;
213
+ let importName = imports.get(importKey);
128
214
 
129
- const replacementKey = JSON.stringify({
130
- importKey,
215
+ if (!importName) {
216
+ importName = `___CSS_LOADER_URL_IMPORT_${imports.size}___`;
217
+ imports.set(importKey, importName);
218
+ options.imports.push({
219
+ importName,
220
+ url: options.urlHandler(newUrl),
221
+ index
222
+ });
223
+ }
224
+
225
+ const {
226
+ needQuotes
227
+ } = rule;
228
+ const replacementKey = JSON.stringify({
229
+ newUrl,
230
+ hash,
231
+ needQuotes
232
+ });
233
+ let replacementName = replacements.get(replacementKey);
234
+
235
+ if (!replacementName) {
236
+ replacementName = `___CSS_LOADER_URL_REPLACEMENT_${replacements.size}___`;
237
+ replacements.set(replacementKey, replacementName);
238
+ options.replacements.push({
239
+ replacementName,
240
+ importName,
131
241
  hash,
132
242
  needQuotes
133
243
  });
134
- let replacementName = replacementsMap.get(replacementKey);
135
-
136
- if (!replacementName) {
137
- replacementName = `___CSS_LOADER_URL_REPLACEMENT_${replacementsMap.size}___`;
138
- replacementsMap.set(replacementKey, replacementName);
139
- result.messages.push({
140
- pluginName,
141
- type: 'url-replacement',
142
- value: {
143
- replacementName,
144
- importName,
145
- hash,
146
- needQuotes
147
- }
148
- });
149
- } // eslint-disable-next-line no-param-reassign
244
+ } // eslint-disable-next-line no-param-reassign
150
245
 
151
246
 
152
- node.type = 'word'; // eslint-disable-next-line no-param-reassign
247
+ rule.node.type = 'word'; // eslint-disable-next-line no-param-reassign
153
248
 
154
- node.value = replacementName;
155
- }); // eslint-disable-next-line no-param-reassign
249
+ rule.node.value = replacementName; // eslint-disable-next-line no-param-reassign
156
250
 
157
251
  decl.value = parsed.toString();
158
- });
252
+ }
253
+
254
+ return Promise.resolve();
159
255
  });
160
256
 
161
257
  exports.default = _default;