Skip to content

Commit d3df855

Browse files
feat: supported supports() and layer() in @import at-rule
1 parent cf3a3a7 commit d3df855

File tree

6 files changed

+147
-31
lines changed

6 files changed

+147
-31
lines changed

src/plugins/postcss-import-parser.js

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,40 @@ function parseNode(atRule, key) {
118118
throw error;
119119
}
120120

121-
const mediaNodes = paramsNodes.slice(1);
121+
const additionalNodes = paramsNodes.slice(1);
122+
123+
let supports;
124+
let layer;
122125
let media;
123126

124-
if (mediaNodes.length > 0) {
125-
media = valueParser.stringify(mediaNodes).trim().toLowerCase();
127+
if (additionalNodes.length > 0) {
128+
let nodes = [];
129+
130+
for (const node of additionalNodes) {
131+
nodes.push(node);
132+
133+
if (
134+
(node.type === "function" && node.value.toLowerCase() === "layer") ||
135+
(node.type === "word" && node.value.toLowerCase() === "layer")
136+
) {
137+
layer = valueParser.stringify(nodes).trim().toLowerCase();
138+
nodes = [];
139+
} else if (
140+
node.type === "function" &&
141+
node.value.toLowerCase() === "supports"
142+
) {
143+
supports = valueParser.stringify(nodes).trim().toLowerCase();
144+
nodes = [];
145+
}
146+
}
147+
148+
if (nodes.length > 0) {
149+
media = valueParser.stringify(nodes).trim().toLowerCase();
150+
}
126151
}
127152

128153
// eslint-disable-next-line consistent-return
129-
return { atRule, prefix, url, media, isRequestable };
154+
return { atRule, prefix, url, layer, supports, media, isRequestable };
130155
}
131156

132157
const plugin = (options = {}) => {
@@ -160,11 +185,23 @@ const plugin = (options = {}) => {
160185

161186
const resolvedAtRules = await Promise.all(
162187
parsedAtRules.map(async (parsedAtRule) => {
163-
const { atRule, isRequestable, prefix, url, media } =
164-
parsedAtRule;
188+
const {
189+
atRule,
190+
isRequestable,
191+
prefix,
192+
url,
193+
layer,
194+
supports,
195+
media,
196+
} = parsedAtRule;
165197

166198
if (options.filter) {
167-
const needKeep = await options.filter(url, media);
199+
const needKeep = await options.filter(
200+
url,
201+
media,
202+
layer,
203+
supports
204+
);
168205

169206
if (!needKeep) {
170207
return;
@@ -192,13 +229,20 @@ const plugin = (options = {}) => {
192229
atRule.remove();
193230

194231
// eslint-disable-next-line consistent-return
195-
return { url: resolvedUrl, media, prefix, isRequestable };
232+
return {
233+
url: resolvedUrl,
234+
layer,
235+
supports,
236+
media,
237+
prefix,
238+
isRequestable,
239+
};
196240
}
197241

198242
atRule.remove();
199243

200244
// eslint-disable-next-line consistent-return
201-
return { url, media, prefix, isRequestable };
245+
return { url, layer, supports, media, prefix, isRequestable };
202246
})
203247
);
204248

@@ -212,10 +256,11 @@ const plugin = (options = {}) => {
212256
continue;
213257
}
214258

215-
const { url, isRequestable, media } = resolvedAtRule;
259+
const { url, isRequestable, layer, supports, media } =
260+
resolvedAtRule;
216261

217262
if (!isRequestable) {
218-
options.api.push({ url, media, index });
263+
options.api.push({ url, layer, supports, media, index });
219264

220265
// eslint-disable-next-line no-continue
221266
continue;
@@ -237,7 +282,7 @@ const plugin = (options = {}) => {
237282
});
238283
}
239284

240-
options.api.push({ importName, media, index });
285+
options.api.push({ importName, layer, supports, media, index });
241286
}
242287
},
243288
};

src/runtime/api.js

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,40 @@ module.exports = (cssWithMappingToString) => {
88
// return the list of modules as css string
99
list.toString = function toString() {
1010
return this.map((item) => {
11-
const content = cssWithMappingToString(item);
11+
let content = "";
12+
13+
if (item[3]) {
14+
content += `@${item[3]} {`;
15+
}
16+
17+
if (item[2]) {
18+
content += `@media ${item[2]} {`;
19+
}
20+
21+
if (item[4]) {
22+
content += `@${item[4]} {`;
23+
}
24+
25+
content += cssWithMappingToString(item);
26+
27+
if (item[4]) {
28+
content += "}";
29+
}
1230

1331
if (item[2]) {
14-
return `@media ${item[2]} {${content}}`;
32+
content += "}";
33+
}
34+
35+
if (item[3]) {
36+
content += "}";
1537
}
1638

1739
return content;
1840
}).join("");
1941
};
2042

2143
// import a list of modules into the list
22-
list.i = function i(modules, mediaQuery, dedupe) {
44+
list.i = function i(modules, mediaQueryList, dedupe, layer, supports) {
2345
if (typeof modules === "string") {
2446
modules = [[null, modules, ""]];
2547
}
@@ -43,11 +65,27 @@ module.exports = (cssWithMappingToString) => {
4365
continue;
4466
}
4567

46-
if (mediaQuery) {
68+
if (mediaQueryList) {
4769
if (!item[2]) {
48-
item[2] = mediaQuery;
70+
item[2] = mediaQueryList;
71+
} else {
72+
item[2] = `${mediaQueryList} and ${item[2]}`;
73+
}
74+
}
75+
76+
if (layer) {
77+
if (!item[3]) {
78+
item[3] = layer;
79+
} else {
80+
item[3] = `${layer} and ${item[3]}`;
81+
}
82+
}
83+
84+
if (supports) {
85+
if (!item[4]) {
86+
item[4] = supports;
4987
} else {
50-
item[2] = `${mediaQuery} and ${item[2]}`;
88+
item[4] = `${supports} and ${item[4]}`;
5189
}
5290
}
5391

src/utils.js

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,32 @@ function normalizeSourceMapForRuntime(map, loaderContext) {
921921
return JSON.stringify(resultMap);
922922
}
923923

924+
function printParams(media, dedupe, supports, layer) {
925+
let result = "";
926+
927+
if (layer) {
928+
result = `, ${JSON.stringify(layer)}`;
929+
}
930+
931+
if (supports) {
932+
result = `, ${JSON.stringify(supports)}${result}`;
933+
}
934+
935+
if (dedupe) {
936+
result = `, true${result}`;
937+
} else if (result.length > 0) {
938+
result = `, false${result}`;
939+
}
940+
941+
if (media) {
942+
result = `${JSON.stringify(media)}${result}`;
943+
} else if (result.length > 0) {
944+
result = `""${result}`;
945+
}
946+
947+
return result;
948+
}
949+
924950
function getModuleCode(result, api, replacements, options, loaderContext) {
925951
if (options.modules.exportOnlyLocals === true) {
926952
return "";
@@ -939,15 +965,22 @@ function getModuleCode(result, api, replacements, options, loaderContext) {
939965
});\n`;
940966

941967
for (const item of api) {
942-
const { url, media, dedupe } = item;
943-
944-
beforeCode += url
945-
? `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(
946-
`@import url(${url});`
947-
)}${media ? `, ${JSON.stringify(media)}` : ""}]);\n`
948-
: `___CSS_LOADER_EXPORT___.i(${item.importName}${
949-
media ? `, ${JSON.stringify(media)}` : dedupe ? ', ""' : ""
950-
}${dedupe ? ", true" : ""});\n`;
968+
const { url, layer, supports, media, dedupe } = item;
969+
970+
if (url) {
971+
// eslint-disable-next-line no-undefined
972+
const printedParam = printParams(media, undefined, supports, layer);
973+
974+
beforeCode += `___CSS_LOADER_EXPORT___.push([module.id, ${JSON.stringify(
975+
`@import url(${url});`
976+
)}${printedParam.length > 0 ? `, ${printedParam}` : ""}]);\n`;
977+
} else {
978+
const printedParam = printParams(media, dedupe, supports, layer);
979+
980+
beforeCode += `___CSS_LOADER_EXPORT___.i(${item.importName}${
981+
printedParam.length > 0 ? `, ${printedParam}` : ""
982+
});\n`;
983+
}
951984
}
952985

953986
for (const item of replacements) {

test/fixtures/import/import.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
@import url( test.css);
88
@import url( test.css );
99
@import url(
10-
test.css
10+
test.css
1111
);
1212
@import url();
1313
@import url('');
@@ -53,7 +53,7 @@ test.css
5353
}
5454

5555
.foo {
56-
@import 'path.css';
56+
@import 'path.css';
5757
}
5858

5959
@import url('./relative.css');

test/fixtures/import/import.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import css from './import.css';
22

3-
__export__ = css;
3+
__export__ = css.toString();
44

55
export default css;

test/import-option.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from "./helpers/index";
1414

1515
describe('"import" option', () => {
16-
it("should work when not specified", async () => {
16+
it.only("should work when not specified", async () => {
1717
const compiler = getCompiler("./import/import.js");
1818
const stats = await compile(compiler);
1919

0 commit comments

Comments
 (0)