Skip to content

Commit 83108aa

Browse files
authored
Fix incorrect cascade layer order when some resources can not be inlined (#574)
1 parent cad0022 commit 83108aa

16 files changed

+120
-11
lines changed

lib/apply-conditions.js

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,38 @@
33
const base64EncodedConditionalImport = require("./base64-encoded-import")
44

55
module.exports = function applyConditions(bundle, atRule) {
6-
bundle.forEach(stmt => {
6+
const firstImportStatementIndex = bundle.findIndex(
7+
stmt => stmt.type === "import",
8+
)
9+
const lastImportStatementIndex = bundle.findLastIndex(
10+
stmt => stmt.type === "import",
11+
)
12+
13+
bundle.forEach((stmt, index) => {
14+
if (stmt.type === "charset" || stmt.type === "warning") {
15+
return
16+
}
17+
718
if (
8-
stmt.type === "charset" ||
9-
stmt.type === "warning" ||
10-
!stmt.conditions?.length
19+
stmt.type === "layer" &&
20+
((index < lastImportStatementIndex && stmt.conditions?.length) ||
21+
(index > firstImportStatementIndex && index < lastImportStatementIndex))
1122
) {
23+
stmt.type = "import"
24+
stmt.node = stmt.node.clone({
25+
name: "import",
26+
params: base64EncodedConditionalImport(
27+
`'data:text/css;base64,${Buffer.from(stmt.node.toString()).toString(
28+
"base64",
29+
)}'`,
30+
stmt.conditions,
31+
),
32+
})
33+
34+
return
35+
}
36+
37+
if (!stmt.conditions?.length) {
1238
return
1339
}
1440

@@ -20,8 +46,15 @@ module.exports = function applyConditions(bundle, atRule) {
2046
return
2147
}
2248

23-
const { nodes } = stmt
24-
const { parent } = nodes[0]
49+
let nodes
50+
let parent
51+
if (stmt.type === "layer") {
52+
nodes = [stmt.node]
53+
parent = stmt.node.parent
54+
} else {
55+
nodes = stmt.nodes
56+
parent = nodes[0].parent
57+
}
2558

2659
const atRules = []
2760

lib/apply-styles.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module.exports = function applyStyles(bundle, styles) {
55

66
// Strip additional statements.
77
bundle.forEach(stmt => {
8-
if (["charset", "import"].includes(stmt.type)) {
8+
if (["charset", "import", "layer"].includes(stmt.type)) {
99
stmt.node.parent = undefined
1010
styles.append(stmt.node)
1111
} else if (stmt.type === "nodes") {

lib/base64-encoded-import.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const formatImportPrelude = require("./format-import-prelude")
88
// To achieve this we create a list of base64 encoded imports, where each import contains a stylesheet with another import.
99
// Each import can define a single group of conditions and a single cascade layer.
1010
module.exports = function base64EncodedConditionalImport(prelude, conditions) {
11+
if (!conditions?.length) return prelude
12+
1113
conditions.reverse()
1214
const first = conditions.pop()
1315
let params = `${prelude} ${formatImportPrelude(

lib/parse-statements.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const { stringify } = valueParser
99
module.exports = function parseStatements(result, styles, conditions, from) {
1010
const statements = []
1111
let nodes = []
12+
let encounteredNonImportNodes = false
1213

1314
styles.each(node => {
1415
let stmt
@@ -17,6 +18,14 @@ module.exports = function parseStatements(result, styles, conditions, from) {
1718
stmt = parseImport(result, node, conditions, from)
1819
else if (node.name === "charset")
1920
stmt = parseCharset(result, node, conditions, from)
21+
else if (
22+
node.name === "layer" &&
23+
!encounteredNonImportNodes &&
24+
!node.nodes
25+
)
26+
stmt = parseLayer(result, node, conditions, from)
27+
} else if (node.type !== "comment") {
28+
encounteredNonImportNodes = true
2029
}
2130

2231
if (stmt) {
@@ -233,3 +242,12 @@ function parseImport(result, atRule, conditions, from) {
233242

234243
return stmt
235244
}
245+
246+
function parseLayer(result, atRule, conditions, from) {
247+
return {
248+
type: "layer",
249+
node: atRule,
250+
conditions: [...conditions],
251+
from,
252+
}
253+
}

lib/parse-styles.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ async function parseStyles(
3333
}
3434

3535
let charset
36-
const imports = []
36+
const beforeBundle = []
3737
const bundle = []
3838

3939
function handleCharset(stmt) {
@@ -56,19 +56,24 @@ async function parseStyles(
5656
else if (stmt.type === "import") {
5757
if (stmt.children) {
5858
stmt.children.forEach((child, index) => {
59-
if (child.type === "import") imports.push(child)
59+
if (child.type === "import") beforeBundle.push(child)
60+
else if (child.type === "layer") beforeBundle.push(child)
6061
else if (child.type === "charset") handleCharset(child)
6162
else bundle.push(child)
6263
// For better output
6364
if (index === 0) child.parent = stmt
6465
})
65-
} else imports.push(stmt)
66+
} else beforeBundle.push(stmt)
67+
} else if (stmt.type === "layer") {
68+
beforeBundle.push(stmt)
6669
} else if (stmt.type === "nodes") {
6770
bundle.push(stmt)
6871
}
6972
})
7073

71-
return charset ? [charset, ...imports.concat(bundle)] : imports.concat(bundle)
74+
return charset
75+
? [charset, ...beforeBundle.concat(bundle)]
76+
: beforeBundle.concat(bundle)
7277
}
7378

7479
async function resolveImportId(result, stmt, options, state, postcss) {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* a comment */
2+
3+
@layer layer-alpha;
4+
@import "http://css";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@layer layer-beta;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@import "layer-only.css" print;
2+
@import "layer-followed-by-ignore.css" screen;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@import 'data:text/css;base64,QGxheWVyIGxheWVyLWJldGE=' print;
2+
@import 'data:text/css;base64,QGxheWVyIGxheWVyLWFscGhh' screen;
3+
@import "http://css" screen;
4+
@media screen{
5+
/* a comment */
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@import "http://css-a";
2+
@import url("layer-only.css");
3+
@import "http://css-b";

0 commit comments

Comments
 (0)