From 3ce0384e9e6dda7f02d483ad9b74f4c06fe05e8b Mon Sep 17 00:00:00 2001 From: Dominic Gannaway Date: Fri, 4 Oct 2024 01:36:58 +0200 Subject: [PATCH] fix: strip internal properties from rest props during SSR (#13492) * fix: strip internal properties from rest props during SSR * address feedback * update snapshots * lint --- .changeset/sour-poems-trade.md | 5 ++++ .../server/visitors/VariableDeclaration.js | 26 ++++++++++++++++++- .../migrate/samples/derivations/output.svelte | 2 +- .../output.svelte | 2 +- .../samples/props-rest-2/Component.svelte | 8 ++++++ .../samples/props-rest-2/_config.js | 5 ++++ .../samples/props-rest-2/main.svelte | 5 ++++ .../samples/props-rest/Component.svelte | 12 +++++++++ .../samples/props-rest/_config.js | 5 ++++ .../samples/props-rest/main.svelte | 5 ++++ .../_expected/server/index.svelte.js | 2 +- 11 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 .changeset/sour-poems-trade.md create mode 100644 packages/svelte/tests/runtime-runes/samples/props-rest-2/Component.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-rest-2/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/props-rest-2/main.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-rest/Component.svelte create mode 100644 packages/svelte/tests/runtime-runes/samples/props-rest/_config.js create mode 100644 packages/svelte/tests/runtime-runes/samples/props-rest/main.svelte diff --git a/.changeset/sour-poems-trade.md b/.changeset/sour-poems-trade.md new file mode 100644 index 0000000000..d6ab60a446 --- /dev/null +++ b/.changeset/sour-poems-trade.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: strip internal properties from rest props during SSR diff --git a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js index 5e0b34a557..31de811ac7 100644 --- a/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js +++ b/packages/svelte/src/compiler/phases/3-transform/server/visitors/VariableDeclaration.js @@ -25,8 +25,14 @@ export function VariableDeclaration(node, context) { } if (rune === '$props') { + let has_rest = false; // remove $bindable() from props declaration - const id = walk(declarator.id, null, { + let id = walk(declarator.id, null, { + RestElement(node, context) { + if (context.path.at(-1) === declarator.id) { + has_rest = true; + } + }, AssignmentPattern(node) { if ( node.right.type === 'CallExpression' && @@ -39,6 +45,24 @@ export function VariableDeclaration(node, context) { } } }); + if (id.type === 'ObjectPattern' && has_rest) { + // If a rest pattern is used within an object pattern, we need to ensure we don't expose $$slots or $$events + id.properties.splice( + id.properties.length - 1, + 0, + // @ts-ignore + b.prop('init', b.id('$$slots'), b.id('$$slots')), + b.prop('init', b.id('$$events'), b.id('$$events')) + ); + } else if (id.type === 'Identifier') { + // If $props is referenced as an identifier, we need to ensure we don't expose $$slots or $$events as properties + // on the identifier reference + id = b.object_pattern([ + b.prop('init', b.id('$$slots'), b.id('$$slots')), + b.prop('init', b.id('$$events'), b.id('$$events')), + b.rest(b.id(id.name)) + ]); + } declarations.push( b.declarator(/** @type {Pattern} */ (context.visit(id)), b.id('$$props')) ); diff --git a/packages/svelte/tests/migrate/samples/derivations/output.svelte b/packages/svelte/tests/migrate/samples/derivations/output.svelte index e797a4da1e..ed6e72dfab 100644 --- a/packages/svelte/tests/migrate/samples/derivations/output.svelte +++ b/packages/svelte/tests/migrate/samples/derivations/output.svelte @@ -8,4 +8,4 @@ let { time_16 } = $derived({ time_16: count * 16 }) -{count} / {doubled} / {quadrupled} / {time_8} / {time_16} +{count} / {doubled} / {quadrupled} / {time_8} / {time_16} \ No newline at end of file diff --git a/packages/svelte/tests/migrate/samples/state-and-derivations-sequence/output.svelte b/packages/svelte/tests/migrate/samples/state-and-derivations-sequence/output.svelte index bd9fe82142..19e6ea1a62 100644 --- a/packages/svelte/tests/migrate/samples/state-and-derivations-sequence/output.svelte +++ b/packages/svelte/tests/migrate/samples/state-and-derivations-sequence/output.svelte @@ -11,4 +11,4 @@ -{count} / {doubled} / {quadrupled} / {time_8} / {time_16} +{count} / {doubled} / {quadrupled} / {time_8} / {time_16} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-runes/samples/props-rest-2/Component.svelte b/packages/svelte/tests/runtime-runes/samples/props-rest-2/Component.svelte new file mode 100644 index 0000000000..d2abcacd64 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-rest-2/Component.svelte @@ -0,0 +1,8 @@ + + diff --git a/packages/svelte/tests/runtime-runes/samples/props-rest-2/_config.js b/packages/svelte/tests/runtime-runes/samples/props-rest-2/_config.js new file mode 100644 index 0000000000..0dc5b26e24 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-rest-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-rest-2/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-rest-2/main.svelte new file mode 100644 index 0000000000..a97c23fedd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-rest-2/main.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-runes/samples/props-rest/Component.svelte b/packages/svelte/tests/runtime-runes/samples/props-rest/Component.svelte new file mode 100644 index 0000000000..b237c464c0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-rest/Component.svelte @@ -0,0 +1,12 @@ + +{@render children?.()} + diff --git a/packages/svelte/tests/runtime-runes/samples/props-rest/_config.js b/packages/svelte/tests/runtime-runes/samples/props-rest/_config.js new file mode 100644 index 0000000000..c1c142a2d0 --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-rest/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'Foo\n' +}); diff --git a/packages/svelte/tests/runtime-runes/samples/props-rest/main.svelte b/packages/svelte/tests/runtime-runes/samples/props-rest/main.svelte new file mode 100644 index 0000000000..a97c23fedd --- /dev/null +++ b/packages/svelte/tests/runtime-runes/samples/props-rest/main.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js index 362d773be1..6fef87d63b 100644 --- a/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js +++ b/packages/svelte/tests/snapshot/samples/props-identifier/_expected/server/index.svelte.js @@ -3,7 +3,7 @@ import * as $ from "svelte/internal/server"; export default function Props_identifier($$payload, $$props) { $.push(); - let props = $$props; + let { $$slots, $$events, ...props } = $$props; props.a; props[a];