Skip to content

Commit b8e7732

Browse files
fix: respected style field from package.json
1 parent fcdc1ab commit b8e7732

File tree

11 files changed

+242
-108
lines changed

11 files changed

+242
-108
lines changed

src/index.js

+12
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,18 @@ export default function loader(content, map, meta) {
4747
plugins.push(icssParser({ urlHandler }));
4848

4949
if (options.import !== false && exportType === 'full') {
50+
const resolver = this.getResolve({
51+
mainFields: ['css', 'style', 'main', '...'],
52+
mainFiles: ['index', '...'],
53+
extensions: ['.css'],
54+
restrictions: [/\.css$/i],
55+
});
56+
5057
plugins.push(
5158
importParser({
59+
context: this.context,
5260
filter: getFilter(options.import, this.resourcePath),
61+
resolver,
5362
urlHandler,
5463
})
5564
);
@@ -125,6 +134,9 @@ export default function loader(content, map, meta) {
125134
}
126135
}
127136

137+
imports.sort((a, b) => a.index - b.index);
138+
apiImports.sort((a, b) => a.index - b.index);
139+
128140
const { localsConvention } = options;
129141
const esModule =
130142
typeof options.esModule !== 'undefined' ? options.esModule : false;

src/plugins/postcss-import-parser.js

+131-96
Original file line numberDiff line numberDiff line change
@@ -2,131 +2,166 @@ import postcss from 'postcss';
22
import valueParser from 'postcss-value-parser';
33
import { isUrlRequest } from 'loader-utils';
44

5-
import { normalizeUrl } from '../utils';
5+
import { normalizeUrl, resolveRequests } from '../utils';
66

77
const pluginName = 'postcss-import-parser';
88

99
export default postcss.plugin(pluginName, (options) => (css, result) => {
10-
const importsMap = new Map();
11-
12-
css.walkAtRules(/^import$/i, (atRule) => {
13-
// Convert only top-level @import
14-
if (atRule.parent.type !== 'root') {
15-
return;
16-
}
17-
18-
// Nodes do not exists - `@import url('http://') :root {}`
19-
if (atRule.nodes) {
20-
result.warn(
21-
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it.",
22-
{ node: atRule }
23-
);
10+
return new Promise((resolve, reject) => {
11+
const importsMap = new Map();
12+
const tasks = [];
2413

25-
return;
26-
}
27-
28-
const { nodes } = valueParser(atRule.params);
29-
30-
// No nodes - `@import ;`
31-
// Invalid type - `@import foo-bar;`
32-
if (
33-
nodes.length === 0 ||
34-
(nodes[0].type !== 'string' && nodes[0].type !== 'function')
35-
) {
36-
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
37-
node: atRule,
38-
});
39-
40-
return;
41-
}
42-
43-
let isStringValue;
44-
let url;
45-
46-
if (nodes[0].type === 'string') {
47-
isStringValue = true;
48-
url = nodes[0].value;
49-
} else if (nodes[0].type === 'function') {
50-
// Invalid function - `@import nourl(test.css);`
51-
if (nodes[0].value.toLowerCase() !== 'url') {
52-
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
53-
node: atRule,
54-
});
14+
// A counter is used instead of an index in callback css.walkAtRules because we mutate AST (atRule.remove())
15+
let index = 0;
5516

17+
css.walkAtRules(/^import$/i, (atRule) => {
18+
// Convert only top-level @import
19+
if (atRule.parent.type !== 'root') {
5620
return;
5721
}
5822

59-
isStringValue =
60-
nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
61-
url = isStringValue
62-
? nodes[0].nodes[0].value
63-
: valueParser.stringify(nodes[0].nodes);
64-
}
23+
// Nodes do not exists - `@import url('http://') :root {}`
24+
if (atRule.nodes) {
25+
result.warn(
26+
"It looks like you didn't end your @import statement correctly. Child nodes are attached to it.",
27+
{ node: atRule }
28+
);
29+
30+
return;
31+
}
6532

66-
// Empty url - `@import "";` or `@import url();`
67-
if (url.trim().length === 0) {
68-
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
69-
node: atRule,
70-
});
33+
const { nodes } = valueParser(atRule.params);
7134

72-
return;
73-
}
35+
// No nodes - `@import ;`
36+
// Invalid type - `@import foo-bar;`
37+
if (
38+
nodes.length === 0 ||
39+
(nodes[0].type !== 'string' && nodes[0].type !== 'function')
40+
) {
41+
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
42+
node: atRule,
43+
});
7444

75-
const isRequestable = isUrlRequest(url);
45+
return;
46+
}
7647

77-
if (isRequestable) {
78-
url = normalizeUrl(url, isStringValue);
48+
let isStringValue;
49+
let url;
50+
51+
if (nodes[0].type === 'string') {
52+
isStringValue = true;
53+
url = nodes[0].value;
54+
} else if (nodes[0].type === 'function') {
55+
// Invalid function - `@import nourl(test.css);`
56+
if (nodes[0].value.toLowerCase() !== 'url') {
57+
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
58+
node: atRule,
59+
});
60+
61+
return;
62+
}
63+
64+
isStringValue =
65+
nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
66+
url = isStringValue
67+
? nodes[0].nodes[0].value
68+
: valueParser.stringify(nodes[0].nodes);
69+
}
7970

80-
// Empty url after normalize - `@import '\
81-
// \
82-
// \
83-
// ';
71+
// Empty url - `@import "";` or `@import url();`
8472
if (url.trim().length === 0) {
8573
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
8674
node: atRule,
8775
});
8876

8977
return;
9078
}
91-
}
92-
93-
const media = valueParser.stringify(nodes.slice(1)).trim().toLowerCase();
94-
95-
if (options.filter && !options.filter({ url, media })) {
96-
return;
97-
}
9879

99-
atRule.remove();
80+
const isRequestable = isUrlRequest(url);
10081

101-
if (isRequestable) {
102-
const importKey = url;
103-
let importName = importsMap.get(importKey);
82+
if (isRequestable) {
83+
url = normalizeUrl(url, isStringValue);
10484

105-
if (!importName) {
106-
importName = `___CSS_LOADER_AT_RULE_IMPORT_${importsMap.size}___`;
107-
importsMap.set(importKey, importName);
85+
// Empty url after normalize - `@import '\
86+
// \
87+
// \
88+
// ';
89+
if (url.trim().length === 0) {
90+
result.warn(`Unable to find uri in "${atRule.toString()}"`, {
91+
node: atRule,
92+
});
10893

109-
result.messages.push({
110-
type: 'import',
111-
value: {
112-
importName,
113-
url: options.urlHandler ? options.urlHandler(url) : url,
114-
},
115-
});
94+
return;
95+
}
11696
}
11797

118-
result.messages.push({
119-
type: 'api-import',
120-
value: { type: 'internal', importName, media },
121-
});
98+
const media = valueParser.stringify(nodes.slice(1)).trim().toLowerCase();
12299

123-
return;
124-
}
100+
if (options.filter && !options.filter({ url, media })) {
101+
return;
102+
}
125103

126-
result.messages.push({
127-
pluginName,
128-
type: 'api-import',
129-
value: { type: 'external', url, media },
104+
atRule.remove();
105+
106+
index += 1;
107+
108+
tasks.push(
109+
Promise.resolve(index).then(async (currentIndex) => {
110+
if (isRequestable) {
111+
const importKey = url;
112+
let importName = importsMap.get(importKey);
113+
114+
if (!importName) {
115+
importName = `___CSS_LOADER_AT_RULE_IMPORT_${importsMap.size}___`;
116+
importsMap.set(importKey, importName);
117+
118+
const { resolver, context } = options;
119+
120+
let resolvedUrl;
121+
122+
try {
123+
resolvedUrl = await resolveRequests(resolver, context, [url]);
124+
} catch (error) {
125+
throw error;
126+
}
127+
128+
result.messages.push({
129+
type: 'import',
130+
value: {
131+
importName,
132+
url: options.urlHandler
133+
? options.urlHandler(resolvedUrl)
134+
: resolvedUrl,
135+
index: currentIndex,
136+
},
137+
});
138+
}
139+
140+
result.messages.push({
141+
type: 'api-import',
142+
value: {
143+
type: 'internal',
144+
importName,
145+
media,
146+
index: currentIndex,
147+
},
148+
});
149+
150+
return;
151+
}
152+
153+
result.messages.push({
154+
pluginName,
155+
type: 'api-import',
156+
value: { type: 'external', url, media, index: currentIndex },
157+
});
158+
})
159+
);
130160
});
161+
162+
Promise.all(tasks).then(
163+
() => resolve(),
164+
(error) => reject(error)
165+
);
131166
});
132167
});

src/utils.js

+21
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,26 @@ function getExportCode(
422422
return `// Exports\n${code}`;
423423
}
424424

425+
async function resolveRequests(resolve, context, possibleRequests) {
426+
if (possibleRequests.length === 0) {
427+
return Promise.reject();
428+
}
429+
430+
return resolve(context, possibleRequests[0])
431+
.then((result) => {
432+
return result;
433+
})
434+
.catch((error) => {
435+
const [, ...tailPossibleRequests] = possibleRequests;
436+
437+
if (tailPossibleRequests.length === 0) {
438+
throw error;
439+
}
440+
441+
return this.resolveRequests(context, tailPossibleRequests);
442+
});
443+
}
444+
425445
export {
426446
normalizeUrl,
427447
getFilter,
@@ -432,4 +452,5 @@ export {
432452
getModuleCode,
433453
getExportCode,
434454
shouldUseModulesPlugins,
455+
resolveRequests,
435456
};

0 commit comments

Comments
 (0)