Skip to content

Commit e751080

Browse files
feat: added support for supports() and layer() in @import at-rule (#843)
1 parent 9d102a3 commit e751080

18 files changed

+323
-24
lines changed

src/index.js

+47-2
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class MiniCssExtractPlugin {
4949
identifier,
5050
identifierIndex,
5151
content,
52+
layer,
53+
supports,
5254
media,
5355
sourceMap,
5456
assets,
@@ -61,6 +63,8 @@ class MiniCssExtractPlugin {
6163
this._identifier = identifier;
6264
this._identifierIndex = identifierIndex;
6365
this.content = content;
66+
this.layer = layer;
67+
this.supports = supports;
6468
this.media = media;
6569
this.sourceMap = sourceMap;
6670
this.assets = assets;
@@ -108,6 +112,8 @@ class MiniCssExtractPlugin {
108112
updateCacheModule(module) {
109113
if (
110114
this.content !== module.content ||
115+
this.layer !== module.layer ||
116+
this.supports !== module.supports ||
111117
this.media !== module.media ||
112118
this.sourceMap !== module.sourceMap ||
113119
this.assets !== module.assets ||
@@ -116,6 +122,8 @@ class MiniCssExtractPlugin {
116122
this._needBuild = true;
117123

118124
this.content = module.content;
125+
this.layer = module.layer;
126+
this.supports = module.supports;
119127
this.media = module.media;
120128
this.sourceMap = module.sourceMap;
121129
this.assets = module.assets;
@@ -150,6 +158,12 @@ class MiniCssExtractPlugin {
150158
const hash = webpack.util.createHash(hashFunction);
151159

152160
hash.update(this.content);
161+
162+
if (this.layer) {
163+
hash.update(this.layer);
164+
}
165+
166+
hash.update(this.supports || "");
153167
hash.update(this.media || "");
154168
hash.update(this.sourceMap || "");
155169

@@ -169,6 +183,8 @@ class MiniCssExtractPlugin {
169183
write(this._identifier);
170184
write(this._identifierIndex);
171185
write(this.content);
186+
write(this.layer);
187+
write(this.supports);
172188
write(this.media);
173189
write(this.sourceMap);
174190
write(this.assets);
@@ -203,16 +219,19 @@ class MiniCssExtractPlugin {
203219
const identifier = read();
204220
const identifierIndex = read();
205221
const content = read();
222+
const layer = read();
223+
const supports = read();
206224
const media = read();
207225
const sourceMap = read();
208226
const assets = read();
209227
const assetsInfo = read();
210-
211228
const dep = new CssModule({
212229
context: contextModule,
213230
identifier,
214231
identifierIndex,
215232
content,
233+
layer,
234+
supports,
216235
media,
217236
sourceMap,
218237
assets,
@@ -239,7 +258,7 @@ class MiniCssExtractPlugin {
239258
// eslint-disable-next-line no-shadow
240259
class CssDependency extends webpack.Dependency {
241260
constructor(
242-
{ identifier, content, media, sourceMap },
261+
{ identifier, content, layer, supports, media, sourceMap },
243262
context,
244263
identifierIndex
245264
) {
@@ -248,6 +267,8 @@ class MiniCssExtractPlugin {
248267
this.identifier = identifier;
249268
this.identifierIndex = identifierIndex;
250269
this.content = content;
270+
this.layer = layer;
271+
this.supports = supports;
251272
this.media = media;
252273
this.sourceMap = sourceMap;
253274
this.context = context;
@@ -271,6 +292,8 @@ class MiniCssExtractPlugin {
271292

272293
write(this.identifier);
273294
write(this.content);
295+
write(this.layer);
296+
write(this.supports);
274297
write(this.media);
275298
write(this.sourceMap);
276299
write(this.context);
@@ -302,6 +325,8 @@ class MiniCssExtractPlugin {
302325
{
303326
identifier: read(),
304327
content: read(),
328+
layer: read(),
329+
supports: read(),
305330
media: read(),
306331
sourceMap: read(),
307332
},
@@ -1024,10 +1049,22 @@ class MiniCssExtractPlugin {
10241049
source.add(header);
10251050
}
10261051

1052+
if (module.supports) {
1053+
source.add(`@supports (${module.supports}) {\n`);
1054+
}
1055+
10271056
if (module.media) {
10281057
source.add(`@media ${module.media} {\n`);
10291058
}
10301059

1060+
const needLayer = typeof module.layer !== "undefined";
1061+
1062+
if (needLayer) {
1063+
source.add(
1064+
`@layer${module.layer.length > 0 ? ` ${module.layer}` : ""} {\n`
1065+
);
1066+
}
1067+
10311068
const { path: filename } = compilation.getPathWithInfo(
10321069
filenameTemplate,
10331070
pathData
@@ -1056,9 +1093,17 @@ class MiniCssExtractPlugin {
10561093

10571094
source.add("\n");
10581095

1096+
if (needLayer) {
1097+
source.add("}\n");
1098+
}
1099+
10591100
if (module.media) {
10601101
source.add("}\n");
10611102
}
1103+
1104+
if (module.supports) {
1105+
source.add("}\n");
1106+
}
10621107
}
10631108
}
10641109

src/loader.js

+26-22
Original file line numberDiff line numberDiff line change
@@ -119,29 +119,33 @@ export function pitch(request) {
119119
if (!Array.isArray(exports)) {
120120
dependencies = [[null, exports]];
121121
} else {
122-
dependencies = exports.map(([id, content, media, sourceMap]) => {
123-
let identifier = id;
124-
let context;
125-
if (compilation) {
126-
const module = findModuleById(compilation, id);
127-
identifier = module.identifier();
128-
({ context } = module);
129-
} else {
130-
// TODO check if this context is used somewhere
131-
context = this.rootContext;
132-
}
122+
dependencies = exports.map(
123+
([id, content, media, sourceMap, supports, layer]) => {
124+
let identifier = id;
125+
let context;
126+
if (compilation) {
127+
const module = findModuleById(compilation, id);
128+
identifier = module.identifier();
129+
({ context } = module);
130+
} else {
131+
// TODO check if this context is used somewhere
132+
context = this.rootContext;
133+
}
133134

134-
return {
135-
identifier,
136-
context,
137-
content: Buffer.from(content),
138-
media,
139-
sourceMap: sourceMap
140-
? Buffer.from(JSON.stringify(sourceMap))
141-
: // eslint-disable-next-line no-undefined
142-
undefined,
143-
};
144-
});
135+
return {
136+
identifier,
137+
context,
138+
content: Buffer.from(content),
139+
media,
140+
supports,
141+
layer,
142+
sourceMap: sourceMap
143+
? Buffer.from(JSON.stringify(sourceMap))
144+
: // eslint-disable-next-line no-undefined
145+
undefined,
146+
};
147+
}
148+
);
145149
}
146150

147151
addDependencies(dependencies);

test/TestCache.test.js

+105
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,111 @@ describe("TestCache", () => {
309309
});
310310
});
311311

312+
it('should work with the "filesystem" cache #2', async () => {
313+
const casesDirectory = path.resolve(__dirname, "cases");
314+
const directoryForCase = path.resolve(casesDirectory, "at-import-layer");
315+
// eslint-disable-next-line import/no-dynamic-require, global-require
316+
const webpackConfig = require(path.resolve(
317+
directoryForCase,
318+
"webpack.config.js"
319+
));
320+
const outputPath = path.resolve(__dirname, "js/cache-filesystem-1");
321+
const fileSystemCacheDirectory = path.resolve(
322+
__dirname,
323+
"./js/.cache/type-filesystem-1"
324+
);
325+
326+
await del([outputPath, fileSystemCacheDirectory]);
327+
328+
const compiler1 = webpack({
329+
...webpackConfig,
330+
mode: "development",
331+
context: directoryForCase,
332+
cache: {
333+
type: "filesystem",
334+
cacheDirectory: fileSystemCacheDirectory,
335+
idleTimeout: 0,
336+
idleTimeoutForInitialStore: 0,
337+
},
338+
output: {
339+
path: outputPath,
340+
},
341+
});
342+
343+
await new Promise((resolve, reject) => {
344+
compiler1.run((error, stats) => {
345+
if (error) {
346+
reject(error);
347+
348+
return;
349+
}
350+
351+
compiler1.close(() => {
352+
expect(Object.keys(stats.compilation.assets).sort())
353+
.toMatchInlineSnapshot(`
354+
Array [
355+
"main.css",
356+
"main.js",
357+
]
358+
`);
359+
expect(Array.from(stats.compilation.emittedAssets).sort())
360+
.toMatchInlineSnapshot(`
361+
Array [
362+
"main.css",
363+
"main.js",
364+
]
365+
`);
366+
expect(stats.compilation.warnings).toHaveLength(0);
367+
expect(stats.compilation.errors).toHaveLength(0);
368+
369+
resolve();
370+
});
371+
});
372+
});
373+
374+
const compiler2 = webpack({
375+
...webpackConfig,
376+
mode: "development",
377+
context: directoryForCase,
378+
cache: {
379+
type: "filesystem",
380+
cacheDirectory: fileSystemCacheDirectory,
381+
idleTimeout: 0,
382+
idleTimeoutForInitialStore: 0,
383+
},
384+
output: {
385+
path: outputPath,
386+
},
387+
});
388+
389+
await new Promise((resolve, reject) => {
390+
compiler2.run((error, stats) => {
391+
if (error) {
392+
reject(error);
393+
394+
return;
395+
}
396+
397+
compiler2.close(() => {
398+
expect(Object.keys(stats.compilation.assets).sort())
399+
.toMatchInlineSnapshot(`
400+
Array [
401+
"main.css",
402+
"main.js",
403+
]
404+
`);
405+
expect(
406+
Array.from(stats.compilation.emittedAssets).sort()
407+
).toMatchInlineSnapshot(`Array []`);
408+
expect(stats.compilation.warnings).toHaveLength(0);
409+
expect(stats.compilation.errors).toHaveLength(0);
410+
411+
resolve();
412+
});
413+
});
414+
});
415+
});
416+
312417
it('should work with the "filesystem" cache and asset modules', async () => {
313418
const casesDirectory = path.resolve(__dirname, "cases");
314419
const directoryForCase = path.resolve(casesDirectory, "asset-modules");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
@layer framework {
2+
@layer base {.bottom {
3+
background: blue;
4+
}
5+
}
6+
}
7+
@layer framework {
8+
@layer base {
9+
.middle {
10+
background: green;
11+
}
12+
}
13+
14+
}
15+
@layer {
16+
.color {
17+
color: red;
18+
}
19+
20+
}
21+
@supports (display: flex) {
22+
@media (prefers-color-scheme: dark) {
23+
@layer default {
24+
@supports (display: grid) {@media screen and (min-width: 900px) {@layer base {.foo {
25+
color: red;
26+
}
27+
}}}
28+
}
29+
}
30+
}
31+
@supports (display: flex) {
32+
@media (prefers-color-scheme: dark) {
33+
@layer default {
34+
/* prettier-ignore */
35+
36+
.bar {
37+
color: blue;
38+
}
39+
40+
}
41+
}
42+
}
43+
/* prettier-ignore */
44+
45+
.top {
46+
background: red;
47+
}
48+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* prettier-ignore */
2+
@import url("./zzz.css") layer(base) supports(display: grid) screen and (min-width: 900px);
3+
4+
.bar {
5+
color: blue;
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
@import url("./test.css") layer(base);
2+
3+
@layer base {
4+
.middle {
5+
background: green;
6+
}
7+
}

test/cases/at-import-layer/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import "./style.css";

test/cases/at-import-layer/style.css

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@import url("./import-with-layer.css") layer(framework);
2+
@import url("./unnamed-layer.css") layer;
3+
/* prettier-ignore */
4+
@import url("./import-with-layer-and-supports-and-media.css") layer(default) supports(display: flex) (prefers-color-scheme: dark);
5+
6+
.top {
7+
background: red;
8+
}

0 commit comments

Comments
 (0)