Skip to content

Commit 3ce0384

Browse files
authored
fix: strip internal properties from rest props during SSR (#13492)
* fix: strip internal properties from rest props during SSR * address feedback * update snapshots * lint
1 parent e850852 commit 3ce0384

File tree

11 files changed

+73
-4
lines changed

11 files changed

+73
-4
lines changed

.changeset/sour-poems-trade.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: strip internal properties from rest props during SSR

packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,14 @@ export function VariableDeclaration(node, context) {
2525
}
2626

2727
if (rune === '$props') {
28+
let has_rest = false;
2829
// remove $bindable() from props declaration
29-
const id = walk(declarator.id, null, {
30+
let id = walk(declarator.id, null, {
31+
RestElement(node, context) {
32+
if (context.path.at(-1) === declarator.id) {
33+
has_rest = true;
34+
}
35+
},
3036
AssignmentPattern(node) {
3137
if (
3238
node.right.type === 'CallExpression' &&
@@ -39,6 +45,24 @@ export function VariableDeclaration(node, context) {
3945
}
4046
}
4147
});
48+
if (id.type === 'ObjectPattern' && has_rest) {
49+
// If a rest pattern is used within an object pattern, we need to ensure we don't expose $$slots or $$events
50+
id.properties.splice(
51+
id.properties.length - 1,
52+
0,
53+
// @ts-ignore
54+
b.prop('init', b.id('$$slots'), b.id('$$slots')),
55+
b.prop('init', b.id('$$events'), b.id('$$events'))
56+
);
57+
} else if (id.type === 'Identifier') {
58+
// If $props is referenced as an identifier, we need to ensure we don't expose $$slots or $$events as properties
59+
// on the identifier reference
60+
id = b.object_pattern([
61+
b.prop('init', b.id('$$slots'), b.id('$$slots')),
62+
b.prop('init', b.id('$$events'), b.id('$$events')),
63+
b.rest(b.id(id.name))
64+
]);
65+
}
4266
declarations.push(
4367
b.declarator(/** @type {Pattern} */ (context.visit(id)), b.id('$$props'))
4468
);

packages/svelte/tests/migrate/samples/derivations/output.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
let { time_16 } = $derived({ time_16: count * 16 })
99
</script>
1010

11-
{count} / {doubled} / {quadrupled} / {time_8} / {time_16}
11+
{count} / {doubled} / {quadrupled} / {time_8} / {time_16}

packages/svelte/tests/migrate/samples/state-and-derivations-sequence/output.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@
1111
<!-- reassign to migrate to state -->
1212
<button onclick={()=> count++}></button>
1313

14-
{count} / {doubled} / {quadrupled} / {time_8} / {time_16}
14+
{count} / {doubled} / {quadrupled} / {time_8} / {time_16}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<script>
2+
let rest = $props();
3+
</script>
4+
<ul>
5+
{#each Object.getOwnPropertyNames(rest) as n}
6+
<li>{n}</li>
7+
{/each}
8+
</ul>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: '<ul><li>name</li><li>title</li><li>children</li></ul>'
5+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
import Component from "./Component.svelte";
3+
</script>
4+
5+
<Component name="n" title="t">Foo</Component>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script>
2+
let {
3+
children,
4+
...rest
5+
} = $props();
6+
</script>
7+
{@render children?.()}
8+
<ul>
9+
{#each Object.getOwnPropertyNames(rest) as n}
10+
<li>{n}</li>
11+
{/each}
12+
</ul>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
html: 'Foo\n<ul><li>name</li><li>title</li></ul>'
5+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
import Component from "./Component.svelte";
3+
</script>
4+
5+
<Component name="n" title="t">Foo</Component>

packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as $ from "svelte/internal/server";
33
export default function Props_identifier($$payload, $$props) {
44
$.push();
55

6-
let props = $$props;
6+
let { $$slots, $$events, ...props } = $$props;
77

88
props.a;
99
props[a];

0 commit comments

Comments
 (0)