Skip to content

Commit 19d80ad

Browse files
fix: css pruning producing invalid css (#14448)
* fix: css pruning producing invalid css * Update .changeset/big-hats-wonder.md --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 4f318e6 commit 19d80ad

File tree

8 files changed

+211
-13
lines changed

8 files changed

+211
-13
lines changed

.changeset/big-hats-wonder.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: correctly remove unused selectors in middle of selector lists

packages/svelte/src/compiler/phases/3-transform/css/index.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ const visitors = {
200200
let pruning = false;
201201
let prune_start = children[0].start;
202202
let last = prune_start;
203+
let has_previous_used = false;
203204

204205
for (let i = 0; i < children.length; i += 1) {
205206
const selector = children[i];
@@ -210,9 +211,9 @@ const visitors = {
210211
while (state.code.original[i] !== ',') i--;
211212

212213
if (state.minify) {
213-
state.code.remove(prune_start, i + 1);
214+
state.code.remove(prune_start, has_previous_used ? i : i + 1);
214215
} else {
215-
state.code.overwrite(i, i + 1, '*/');
216+
state.code.appendRight(has_previous_used ? i : i + 1, '*/');
216217
}
217218
} else {
218219
if (i === 0) {
@@ -222,24 +223,21 @@ const visitors = {
222223
state.code.prependRight(selector.start, '/* (unused) ');
223224
}
224225
} else {
225-
// If this is not the last selector add a separator
226-
const separator = i !== children.length - 1 ? ',' : '';
227-
228226
if (state.minify) {
229227
prune_start = last;
230-
if (separator) {
231-
while (state.code.original[prune_start - 1] !== ',') prune_start++;
232-
state.code.update(last, prune_start, separator);
233-
}
234228
} else {
235-
state.code.overwrite(last, selector.start, `${separator} /* (unused) `);
229+
state.code.overwrite(last, selector.start, ` /* (unused) `);
236230
}
237231
}
238232
}
239233

240234
pruning = !pruning;
241235
}
242236

237+
if (!pruning && selector.metadata.used) {
238+
has_previous_used = true;
239+
}
240+
243241
last = selector.end;
244242
}
245243

packages/svelte/tests/css/samples/has/expected.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
/* (unused) .unused x:has(y) {
7676
color: red;
7777
}*/
78-
/* (unused) .unused:has(.unused)*/ x.svelte-xyz:has(y:where(.svelte-xyz)) {
78+
/* (unused) .unused:has(.unused),*/ x.svelte-xyz:has(y:where(.svelte-xyz)) {
7979
color: green;
8080
}
8181

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
h1.svelte-xyz,
33
h2.svelte-xyz,
4-
h3.svelte-xyz, /* (unused) h4*/
4+
h3.svelte-xyz /* (unused) h4*/,
55
p.svelte-xyz {
66
color: red;
77
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
/* (unused) .foo*/ .bar.svelte-xyz /* (unused) .baz*/ {
1+
/* (unused) .foo,*/ .bar.svelte-xyz /* (unused) .baz*/ {
22
color: red;
33
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
warnings: [
5+
{
6+
code: 'a11y_missing_content',
7+
message: '`<h1>` element should contain text',
8+
start: {
9+
line: 1,
10+
column: 0,
11+
character: 0
12+
},
13+
end: {
14+
line: 1,
15+
column: 9,
16+
character: 9
17+
}
18+
},
19+
{
20+
code: 'a11y_missing_content',
21+
message: '`<h4>` element should contain text',
22+
start: {
23+
line: 2,
24+
column: 0,
25+
character: 10
26+
},
27+
end: {
28+
line: 2,
29+
column: 9,
30+
character: 19
31+
}
32+
},
33+
{
34+
code: 'css_unused_selector',
35+
message: 'Unused CSS selector "h2"',
36+
start: {
37+
line: 6,
38+
column: 5,
39+
character: 35
40+
},
41+
end: {
42+
line: 6,
43+
column: 7,
44+
character: 37
45+
}
46+
},
47+
{
48+
code: 'css_unused_selector',
49+
message: 'Unused CSS selector "h3"',
50+
start: {
51+
line: 6,
52+
column: 9,
53+
character: 39
54+
},
55+
end: {
56+
line: 6,
57+
column: 11,
58+
character: 41
59+
}
60+
},
61+
{
62+
code: 'css_unused_selector',
63+
message: 'Unused CSS selector "h2"',
64+
start: {
65+
line: 9,
66+
column: 5,
67+
character: 66
68+
},
69+
end: {
70+
line: 9,
71+
column: 7,
72+
character: 68
73+
}
74+
},
75+
{
76+
code: 'css_unused_selector',
77+
message: 'Unused CSS selector "h2"',
78+
start: {
79+
line: 13,
80+
column: 5,
81+
character: 110
82+
},
83+
end: {
84+
line: 13,
85+
column: 7,
86+
character: 112
87+
}
88+
},
89+
{
90+
code: 'css_unused_selector',
91+
message: 'Unused CSS selector "h3"',
92+
start: {
93+
line: 13,
94+
column: 9,
95+
character: 114
96+
},
97+
end: {
98+
line: 13,
99+
column: 11,
100+
character: 116
101+
}
102+
},
103+
{
104+
code: 'css_unused_selector',
105+
message: 'Unused CSS selector "h2"',
106+
start: {
107+
line: 17,
108+
column: 5,
109+
character: 161
110+
},
111+
end: {
112+
line: 17,
113+
column: 7,
114+
character: 163
115+
}
116+
},
117+
{
118+
code: 'css_unused_selector',
119+
message: 'Unused CSS selector "h3"',
120+
start: {
121+
line: 17,
122+
column: 9,
123+
character: 165
124+
},
125+
end: {
126+
line: 17,
127+
column: 11,
128+
character: 167
129+
}
130+
},
131+
{
132+
code: 'css_unused_selector',
133+
message: 'Unused CSS selector "h5"',
134+
start: {
135+
line: 17,
136+
column: 17,
137+
character: 173
138+
},
139+
end: {
140+
line: 17,
141+
column: 19,
142+
character: 175
143+
}
144+
},
145+
{
146+
code: 'css_unused_selector',
147+
message: 'Unused CSS selector "h6"',
148+
start: {
149+
line: 17,
150+
column: 21,
151+
character: 177
152+
},
153+
end: {
154+
line: 17,
155+
column: 23,
156+
character: 179
157+
}
158+
}
159+
]
160+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
h1.svelte-xyz /* (unused) h2, h3*/ {
3+
color: red;
4+
}
5+
h1.svelte-xyz /* (unused) h2*/ {
6+
text-decoration: underline;
7+
}
8+
9+
h1.svelte-xyz /* (unused) h2, h3*/, h4.svelte-xyz {
10+
text-transform: uppercase;
11+
}
12+
13+
h1.svelte-xyz /* (unused) h2, h3*/, h4.svelte-xyz /* (unused) h5, h6*/ {
14+
background-color: green;
15+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<h1></h1>
2+
<h4></h4>
3+
4+
5+
<style>
6+
h1, h2, h3 {
7+
color: red;
8+
}
9+
h1, h2 {
10+
text-decoration: underline;
11+
}
12+
13+
h1, h2, h3, h4 {
14+
text-transform: uppercase;
15+
}
16+
17+
h1, h2, h3, h4, h5, h6 {
18+
background-color: green;
19+
}
20+
</style>

0 commit comments

Comments
 (0)