Skip to content

Commit 263427e

Browse files
refactor: code
1 parent c5062db commit 263427e

File tree

6 files changed

+432
-301
lines changed

6 files changed

+432
-301
lines changed

src/plugins/postcss-import-parser.js

+114-115
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ import {
88
webpackIgnoreCommentRegexp,
99
} from "../utils";
1010

11-
function visitor(result, parsedResults, node, key) {
11+
function parseNode(atRule, key) {
1212
// Convert only top-level @import
13-
if (node.parent.type !== "root") {
13+
if (atRule.parent.type !== "root") {
1414
return;
1515
}
1616

1717
if (
18-
node.raws &&
19-
node.raws.afterName &&
20-
node.raws.afterName.trim().length > 0
18+
atRule.raws &&
19+
atRule.raws.afterName &&
20+
atRule.raws.afterName.trim().length > 0
2121
) {
22-
const lastCommentIndex = node.raws.afterName.lastIndexOf("/*");
23-
const matched = node.raws.afterName
22+
const lastCommentIndex = atRule.raws.afterName.lastIndexOf("/*");
23+
const matched = atRule.raws.afterName
2424
.slice(lastCommentIndex)
2525
.match(webpackIgnoreCommentRegexp);
2626

@@ -29,7 +29,7 @@ function visitor(result, parsedResults, node, key) {
2929
}
3030
}
3131

32-
const prevNode = node.prev();
32+
const prevNode = atRule.prev();
3333

3434
if (prevNode && prevNode.type === "comment") {
3535
const matched = prevNode.text.match(webpackIgnoreCommentRegexp);
@@ -40,26 +40,29 @@ function visitor(result, parsedResults, node, key) {
4040
}
4141

4242
// Nodes do not exists - `@import url('http://') :root {}`
43-
if (node.nodes) {
44-
result.warn(
45-
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it.",
46-
{ node }
43+
if (atRule.nodes) {
44+
const error = new Error(
45+
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it."
4746
);
4847

49-
return;
48+
error.node = atRule;
49+
50+
throw error;
5051
}
5152

52-
const { nodes: paramsNodes } = valueParser(node[key]);
53+
const { nodes: paramsNodes } = valueParser(atRule[key]);
5354

5455
// No nodes - `@import ;`
5556
// Invalid type - `@import foo-bar;`
5657
if (
5758
paramsNodes.length === 0 ||
5859
(paramsNodes[0].type !== "string" && paramsNodes[0].type !== "function")
5960
) {
60-
result.warn(`Unable to find uri in "${node.toString()}"`, { node });
61+
const error = new Error(`Unable to find uri in "${atRule.toString()}"`);
6162

62-
return;
63+
error.node = atRule;
64+
65+
throw error;
6366
}
6467

6568
let isStringValue;
@@ -71,9 +74,11 @@ function visitor(result, parsedResults, node, key) {
7174
} else {
7275
// Invalid function - `@import nourl(test.css);`
7376
if (paramsNodes[0].value.toLowerCase() !== "url") {
74-
result.warn(`Unable to find uri in "${node.toString()}"`, { node });
77+
const error = new Error(`Unable to find uri in "${atRule.toString()}"`);
7578

76-
return;
79+
error.node = atRule;
80+
81+
throw error;
7782
}
7883

7984
isStringValue =
@@ -84,145 +89,139 @@ function visitor(result, parsedResults, node, key) {
8489
: valueParser.stringify(paramsNodes[0].nodes);
8590
}
8691

92+
url = normalizeUrl(url, isStringValue);
93+
94+
const isRequestable = isUrlRequestable(url);
95+
let prefix;
96+
97+
if (isRequestable) {
98+
const queryParts = url.split("!");
99+
100+
if (queryParts.length > 1) {
101+
url = queryParts.pop();
102+
prefix = queryParts.join("!");
103+
}
104+
}
105+
87106
// Empty url - `@import "";` or `@import url();`
88107
if (url.trim().length === 0) {
89-
result.warn(`Unable to find uri in "${node.toString()}"`, { node });
108+
const error = new Error(`Unable to find uri in "${atRule.toString()}"`);
90109

91-
return;
110+
error.node = atRule;
111+
112+
throw error;
113+
}
114+
115+
const mediaNodes = paramsNodes.slice(1);
116+
let media;
117+
118+
if (mediaNodes.length > 0) {
119+
media = valueParser.stringify(mediaNodes).trim().toLowerCase();
92120
}
93121

94-
parsedResults.push({
95-
node,
96-
url,
97-
isStringValue,
98-
mediaNodes: paramsNodes.slice(1),
99-
});
122+
// eslint-disable-next-line consistent-return
123+
return { atRule, prefix, url, media, isRequestable };
100124
}
101125

102126
const plugin = (options = {}) => {
103127
return {
104128
postcssPlugin: "postcss-import-parser",
105129
prepare(result) {
106-
const parsedResults = [];
130+
const parsedAtRules = [];
107131

108132
return {
109133
AtRule: {
110134
import(atRule) {
111-
visitor(result, parsedResults, atRule, "params");
135+
let parsedAtRule;
136+
137+
try {
138+
parsedAtRule = parseNode(atRule, "params", result);
139+
} catch (error) {
140+
result.warn(error.message, { node: error.node });
141+
}
142+
143+
if (!parsedAtRule) {
144+
return;
145+
}
146+
147+
parsedAtRules.push(parsedAtRule);
112148
},
113149
},
114150
async OnceExit() {
115-
if (parsedResults.length === 0) {
151+
if (parsedAtRules.length === 0) {
116152
return;
117153
}
118154

119-
const imports = new Map();
120-
const tasks = [];
121-
122-
for (const parsedResult of parsedResults) {
123-
const { node, url, isStringValue, mediaNodes } = parsedResult;
155+
const resolvedAtRules = await Promise.all(
156+
parsedAtRules.map(async (parsedAtRule) => {
157+
const {
158+
atRule,
159+
isRequestable,
160+
prefix,
161+
url,
162+
media,
163+
} = parsedAtRule;
164+
165+
if (options.filter) {
166+
const needKeep = await options.filter(url, media);
167+
168+
if (!needKeep) {
169+
return null;
170+
}
171+
}
124172

125-
let normalizedUrl = url;
126-
let prefix = "";
173+
atRule.remove();
127174

128-
const isRequestable = isUrlRequestable(normalizedUrl);
175+
if (isRequestable) {
176+
const request = requestify(url, options.rootContext);
129177

130-
if (isRequestable) {
131-
const queryParts = normalizedUrl.split("!");
178+
const { resolver, context } = options;
179+
const resolvedUrl = await resolveRequests(resolver, context, [
180+
...new Set([request, url]),
181+
]);
132182

133-
if (queryParts.length > 1) {
134-
normalizedUrl = queryParts.pop();
135-
prefix = queryParts.join("!");
183+
return { url: resolvedUrl, media, prefix, isRequestable };
136184
}
137185

138-
normalizedUrl = normalizeUrl(normalizedUrl, isStringValue);
139-
140-
// Empty url after normalize - `@import '\
141-
// \
142-
// \
143-
// ';
144-
if (normalizedUrl.trim().length === 0) {
145-
result.warn(`Unable to find uri in "${node.toString()}"`, {
146-
node,
147-
});
186+
return { url, media, prefix, isRequestable };
187+
})
188+
);
148189

149-
// eslint-disable-next-line no-continue
150-
continue;
151-
}
152-
}
190+
const urlToNameMap = new Map();
153191

154-
let media;
192+
for (let index = 0; index <= resolvedAtRules.length - 1; index++) {
193+
const resolvedAtRule = resolvedAtRules[index];
155194

156-
if (mediaNodes.length > 0) {
157-
media = valueParser.stringify(mediaNodes).trim().toLowerCase();
195+
if (!resolvedAtRule) {
196+
// eslint-disable-next-line no-continue
197+
continue;
158198
}
159199

160-
tasks.push(
161-
(async () => {
162-
if (options.filter) {
163-
const processURL = await options.filter(normalizedUrl, media);
164-
if (!processURL) {
165-
return null;
166-
}
167-
}
168-
169-
node.remove();
170-
171-
if (isRequestable) {
172-
const request = requestify(
173-
normalizedUrl,
174-
options.rootContext
175-
);
176-
177-
const { resolver, context } = options;
178-
const resolvedUrl = await resolveRequests(resolver, context, [
179-
...new Set([request, normalizedUrl]),
180-
]);
200+
const { url, isRequestable, media } = resolvedAtRule;
181201

182-
return { url: resolvedUrl, media, prefix, isRequestable };
183-
}
184-
185-
return { url, media, prefix, isRequestable };
186-
})()
187-
);
188-
}
202+
if (!isRequestable) {
203+
options.api.push({ url, media, index });
189204

190-
const results = await Promise.all(tasks);
191-
192-
for (let index = 0; index <= results.length - 1; index++) {
193-
const item = results[index];
194-
195-
if (item === null) {
196205
// eslint-disable-next-line no-continue
197206
continue;
198207
}
199208

200-
const { url, isRequestable, media } = item;
201-
202-
if (isRequestable) {
203-
const { prefix } = item;
204-
const newUrl = prefix ? `${prefix}!${url}` : url;
205-
const importKey = newUrl;
206-
let importName = imports.get(importKey);
209+
const { prefix } = resolvedAtRule;
210+
const newUrl = prefix ? `${prefix}!${url}` : url;
211+
let importName = urlToNameMap.get(newUrl);
207212

208-
if (!importName) {
209-
importName = `___CSS_LOADER_AT_RULE_IMPORT_${imports.size}___`;
210-
imports.set(importKey, importName);
213+
if (!importName) {
214+
importName = `___CSS_LOADER_AT_RULE_IMPORT_${urlToNameMap.size}___`;
215+
urlToNameMap.set(newUrl, importName);
211216

212-
options.imports.push({
213-
importName,
214-
url: options.urlHandler(newUrl),
215-
index,
216-
});
217-
}
218-
219-
options.api.push({ importName, media, index });
220-
221-
// eslint-disable-next-line no-continue
222-
continue;
217+
options.imports.push({
218+
importName,
219+
url: options.urlHandler(newUrl),
220+
index,
221+
});
223222
}
224223

225-
options.api.push({ url, media, index });
224+
options.api.push({ importName, media, index });
226225
}
227226
},
228227
};

0 commit comments

Comments
 (0)