Skip to content

Commit e035e28

Browse files
7nik7nik
and
7nik
authored
Fix: consider component and its snippets during css pruning (#15630)
* fix: consider component and its snippets during css pruning * add changeset * fix: avoid iterator.map --------- Co-authored-by: 7nik <[email protected]>
1 parent c822f9b commit e035e28

File tree

12 files changed

+108
-39
lines changed

12 files changed

+108
-39
lines changed

.changeset/nervous-humans-flash.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: better consider component and its snippets during css pruning

packages/svelte/src/compiler/phases/2-analyze/css/css-prune.js

+19-7
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,11 @@ function apply_combinator(relative_selector, rest_selectors, rule, node, directi
251251
let sibling_matched = false;
252252

253253
for (const possible_sibling of siblings.keys()) {
254-
if (possible_sibling.type === 'RenderTag' || possible_sibling.type === 'SlotElement') {
254+
if (
255+
possible_sibling.type === 'RenderTag' ||
256+
possible_sibling.type === 'SlotElement' ||
257+
possible_sibling.type === 'Component'
258+
) {
255259
// `{@render foo()}<p>foo</p>` with `:global(.x) + p` is a match
256260
if (rest_selectors.length === 1 && rest_selectors[0].metadata.is_global) {
257261
sibling_matched = true;
@@ -814,10 +818,10 @@ function get_element_parent(node) {
814818
* @param {Direction} direction
815819
* @param {boolean} adjacent_only
816820
* @param {Set<Compiler.AST.SnippetBlock>} seen
817-
* @returns {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement | Compiler.AST.SlotElement | Compiler.AST.RenderTag, NodeExistsValue>}
821+
* @returns {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement | Compiler.AST.SlotElement | Compiler.AST.RenderTag | Compiler.AST.Component, NodeExistsValue>}
818822
*/
819823
function get_possible_element_siblings(node, direction, adjacent_only, seen = new Set()) {
820-
/** @type {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement | Compiler.AST.SlotElement | Compiler.AST.RenderTag, NodeExistsValue>} */
824+
/** @type {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement | Compiler.AST.SlotElement | Compiler.AST.RenderTag | Compiler.AST.Component, NodeExistsValue>} */
821825
const result = new Map();
822826
const path = node.metadata.path;
823827

@@ -847,14 +851,18 @@ function get_possible_element_siblings(node, direction, adjacent_only, seen = ne
847851
}
848852
// Special case: slots, render tags and svelte:element tags could resolve to no siblings,
849853
// so we want to continue until we find a definite sibling even with the adjacent-only combinator
850-
} else if (is_block(node)) {
851-
if (node.type === 'SlotElement') {
854+
} else if (is_block(node) || node.type === 'Component') {
855+
if (node.type === 'SlotElement' || node.type === 'Component') {
852856
result.set(node, NODE_PROBABLY_EXISTS);
853857
}
854858

855859
const possible_last_child = get_possible_nested_siblings(node, direction, adjacent_only);
856860
add_to_map(possible_last_child, result);
857-
if (adjacent_only && has_definite_elements(possible_last_child)) {
861+
if (
862+
adjacent_only &&
863+
node.type !== 'Component' &&
864+
has_definite_elements(possible_last_child)
865+
) {
858866
return result;
859867
}
860868
} else if (node.type === 'SvelteElement') {
@@ -907,7 +915,7 @@ function get_possible_element_siblings(node, direction, adjacent_only, seen = ne
907915
}
908916

909917
/**
910-
* @param {Compiler.AST.EachBlock | Compiler.AST.IfBlock | Compiler.AST.AwaitBlock | Compiler.AST.KeyBlock | Compiler.AST.SlotElement | Compiler.AST.SnippetBlock} node
918+
* @param {Compiler.AST.EachBlock | Compiler.AST.IfBlock | Compiler.AST.AwaitBlock | Compiler.AST.KeyBlock | Compiler.AST.SlotElement | Compiler.AST.SnippetBlock | Compiler.AST.Component} node
911919
* @param {Direction} direction
912920
* @param {boolean} adjacent_only
913921
* @param {Set<Compiler.AST.SnippetBlock>} seen
@@ -942,6 +950,10 @@ function get_possible_nested_siblings(node, direction, adjacent_only, seen = new
942950
seen.add(node);
943951
fragments.push(node.body);
944952
break;
953+
954+
case 'Component':
955+
fragments.push(node.fragment, ...[...node.metadata.snippets].map((s) => s.body));
956+
break;
945957
}
946958

947959
/** @type {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement, NodeExistsValue>} NodeMap */

packages/svelte/tests/css/samples/general-siblings-combinator-slot/_config.js

+6-18
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,20 @@ export default test({
55
{
66
code: 'css_unused_selector',
77
message: 'Unused CSS selector ".b ~ .c"',
8-
start: { character: 137, column: 1, line: 11 },
9-
end: { character: 144, column: 8, line: 11 }
8+
start: { character: 191, column: 1, line: 13 },
9+
end: { character: 198, column: 8, line: 13 }
1010
},
1111
{
1212
code: 'css_unused_selector',
1313
message: 'Unused CSS selector ".c ~ .f"',
14-
start: { character: 162, column: 1, line: 12 },
15-
end: { character: 169, column: 8, line: 12 }
16-
},
17-
{
18-
code: 'css_unused_selector',
19-
message: 'Unused CSS selector ".f ~ .g"',
20-
start: { character: 187, column: 1, line: 13 },
21-
end: { character: 194, column: 8, line: 13 }
14+
start: { character: 216, column: 1, line: 14 },
15+
end: { character: 223, column: 8, line: 14 }
2216
},
2317
{
2418
code: 'css_unused_selector',
2519
message: 'Unused CSS selector ".b ~ .f"',
26-
start: { character: 212, column: 1, line: 14 },
27-
end: { character: 219, column: 8, line: 14 }
28-
},
29-
{
30-
code: 'css_unused_selector',
31-
message: 'Unused CSS selector ".b ~ .g"',
32-
start: { character: 237, column: 1, line: 15 },
33-
end: { character: 244, column: 8, line: 15 }
20+
start: { character: 241, column: 1, line: 15 },
21+
end: { character: 248, column: 8, line: 15 }
3422
}
3523
]
3624
});

packages/svelte/tests/css/samples/general-siblings-combinator-slot/expected.css

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
.d.svelte-xyz ~ .e:where(.svelte-xyz) { color: green; }
33
.a.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
44
.a.svelte-xyz ~ .b:where(.svelte-xyz) { color: green; }
5+
.f.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
6+
.b.svelte-xyz ~ .g:where(.svelte-xyz) { color: green; }
57

68
/* no match */
79
/* (unused) .b ~ .c { color: red; }*/
810
/* (unused) .c ~ .f { color: red; }*/
9-
/* (unused) .f ~ .g { color: red; }*/
1011
/* (unused) .b ~ .f { color: red; }*/
11-
/* (unused) .b ~ .g { color: red; }*/

packages/svelte/tests/css/samples/general-siblings-combinator-slot/input.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
.d ~ .e { color: green; }
77
.a ~ .g { color: green; }
88
.a ~ .b { color: green; }
9+
.f ~ .g { color: green; }
10+
.b ~ .g { color: green; }
911
1012
/* no match */
1113
.b ~ .c { color: red; }
1214
.c ~ .f { color: red; }
13-
.f ~ .g { color: red; }
1415
.b ~ .f { color: red; }
15-
.b ~ .g { color: red; }
1616
</style>
1717

1818
<div class="a"></div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
let { foo } = $props();
3+
</script>
4+
5+
{@render foo()}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
warnings: [
5+
{
6+
code: 'css_unused_selector',
7+
message: 'Unused CSS selector "n + m"',
8+
end: {
9+
character: 468,
10+
column: 6,
11+
line: 36
12+
},
13+
start: {
14+
character: 463,
15+
column: 1,
16+
line: 36
17+
}
18+
}
19+
]
20+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
x.svelte-xyz + y:where(.svelte-xyz) { color: green; }
2+
x.svelte-xyz + v:where(.svelte-xyz) { color: green; }
3+
x.svelte-xyz + z:where(.svelte-xyz) { color: green; }
4+
y.svelte-xyz + z:where(.svelte-xyz) { color: green; }
5+
v.svelte-xyz + z:where(.svelte-xyz) { color: green; }
6+
.component + z.svelte-xyz { color: green; }
7+
8+
/* (unused) n + m { color: red; }*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<script>
2+
import Child from './Child.svelte';
3+
</script>
4+
5+
<div>
6+
<x></x>
7+
<Child>
8+
<y></y>
9+
{#snippet foo()}
10+
<v></v>
11+
{/snippet}
12+
</Child>
13+
<z></z>
14+
15+
<Child>
16+
<span>
17+
<n></n>
18+
</span>
19+
{#snippet foo()}
20+
<span>
21+
<n></n>
22+
</span>
23+
{/snippet}
24+
</Child>
25+
<m></m>
26+
</div>
27+
28+
<style>
29+
x + y { color: green; }
30+
x + v { color: green; }
31+
x + z { color: green; }
32+
y + z { color: green; }
33+
v + z { color: green; }
34+
:global(.component) + z { color: green; }
35+
36+
n + m { color: red; }
37+
</style>

packages/svelte/tests/css/samples/siblings-combinator-slot/_config.js

+2-8
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,8 @@ export default test({
55
{
66
code: 'css_unused_selector',
77
message: 'Unused CSS selector ".b + .c"',
8-
start: { character: 110, column: 1, line: 10 },
9-
end: { character: 117, column: 8, line: 10 }
10-
},
11-
{
12-
code: 'css_unused_selector',
13-
message: 'Unused CSS selector ".c + .f"',
14-
start: { character: 135, column: 1, line: 11 },
15-
end: { character: 142, column: 8, line: 11 }
8+
start: { character: 137, column: 1, line: 11 },
9+
end: { character: 144, column: 8, line: 11 }
1610
}
1711
]
1812
});
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
.d.svelte-xyz + .e:where(.svelte-xyz) { color: green; }
33
.a.svelte-xyz + .b:where(.svelte-xyz) { color: green; }
4+
.c.svelte-xyz + .f:where(.svelte-xyz) { color: green; }
45

56
/* no match */
67
/* (unused) .b + .c { color: red; }*/
7-
/* (unused) .c + .f { color: red; }*/

packages/svelte/tests/css/samples/siblings-combinator-slot/input.svelte

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
<style>
66
.d + .e { color: green; }
77
.a + .b { color: green; }
8+
.c + .f { color: green; }
89
910
/* no match */
1011
.b + .c { color: red; }
11-
.c + .f { color: red; }
1212
</style>
1313

1414
<div class="a"></div>

0 commit comments

Comments
 (0)