Skip to content

Commit e9dfe3d

Browse files
feat: supported supports() and layer() in @import at-rule
1 parent 7c2cede commit e9dfe3d

File tree

6 files changed

+147
-31
lines changed

6 files changed

+147
-31
lines changed

src/plugins/postcss-import-parser.js

+57-12
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

+44-6
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,32 @@ module.exports = function (cssWithMappingToString) {
1010
// return the list of modules as css string
1111
list.toString = function toString() {
1212
return this.map((item) => {
13-
const content = cssWithMappingToString(item);
13+
let content = "";
14+
15+
if (item[4]) {
16+
content += `@${item[4]} {`;
17+
}
18+
19+
if (item[3]) {
20+
content += `@${item[3]} {`;
21+
}
22+
23+
if (item[2]) {
24+
content += `@media ${item[2]} {`;
25+
}
26+
27+
content += cssWithMappingToString(item);
1428

1529
if (item[2]) {
16-
return `@media ${item[2]} {${content}}`;
30+
content += "}";
31+
}
32+
33+
if (item[3]) {
34+
content += "}";
35+
}
36+
37+
if (item[4]) {
38+
content += "}";
1739
}
1840

1941
return content;
@@ -22,7 +44,7 @@ module.exports = function (cssWithMappingToString) {
2244

2345
// import a list of modules into the list
2446
// eslint-disable-next-line func-names
25-
list.i = function (modules, mediaQuery, dedupe) {
47+
list.i = function (modules, mediaQueryList, dedupe, layer, supports) {
2648
if (typeof modules === "string") {
2749
// eslint-disable-next-line no-param-reassign
2850
modules = [[null, modules, ""]];
@@ -49,11 +71,27 @@ module.exports = function (cssWithMappingToString) {
4971
continue;
5072
}
5173

52-
if (mediaQuery) {
74+
if (mediaQueryList) {
5375
if (!item[2]) {
54-
item[2] = mediaQuery;
76+
item[2] = mediaQueryList;
77+
} else {
78+
item[2] = `${mediaQueryList} and ${item[2]}`;
79+
}
80+
}
81+
82+
if (layer) {
83+
if (!item[3]) {
84+
item[3] = layer;
85+
} else {
86+
item[3] = `${layer} and ${item[3]}`;
87+
}
88+
}
89+
90+
if (supports) {
91+
if (!item[4]) {
92+
item[4] = supports;
5593
} else {
56-
item[2] = `${mediaQuery} and ${item[2]}`;
94+
item[4] = `${supports} and ${item[4]}`;
5795
}
5896
}
5997

src/utils.js

+42-9
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

+2-2
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

+1-1
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

+1-1
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)