Skip to content

Commit e42bb61

Browse files
fix: ensure components always return an object (#12290)
Closes #12287 --------- Co-authored-by: Simon H <5968653+dummdidumm@users.noreply.github.com> Co-authored-by: Simon Holthausen <simon.holthausen@vercel.com>
1 parent 831552f commit e42bb61

File tree

15 files changed

+74
-0
lines changed

15 files changed

+74
-0
lines changed

.changeset/warm-waves-reply.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: ensure component always returns an object

packages/svelte/src/compiler/phases/3-transform/client/transform-client.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ export function client_component(source, analysis, options) {
339339
? b.return(b.call('$.pop', b.object(component_returned_object)))
340340
: b.stmt(b.call('$.pop'))
341341
);
342+
} else {
343+
// Always return an object, so that `bind:this` on this component will not be falsy
344+
component_block.body.push(b.return(b.object(component_returned_object)));
342345
}
343346

344347
if (analysis.uses_rest_props) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
export const a = {};
3+
</script>
4+
5+
<div>a</div>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<div>b</div>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { flushSync } from 'svelte';
2+
import { test } from '../../test';
3+
4+
export default test({
5+
html: `<button>a</button><button>b</button><div>a</div>`,
6+
compileOptions: {
7+
dev: false
8+
},
9+
10+
async test({ assert, target, logs, ok }) {
11+
const [btn1, btn2] = target.querySelectorAll('button');
12+
13+
flushSync(() => {
14+
btn2.click();
15+
});
16+
17+
assert.htmlEqual(target.innerHTML, `<button>a</button><button>b</button><div>b</div>`);
18+
19+
flushSync(() => {
20+
btn1.click();
21+
});
22+
23+
assert.htmlEqual(target.innerHTML, `<button>a</button><button>b</button><div>a</div>`);
24+
assert.deepEqual(logs, [{ a: {} }, {}, { a: {} }]);
25+
}
26+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script>
2+
import ComponentA from './ComponentA.svelte';
3+
import ComponentB from './ComponentB.svelte';
4+
5+
let type = $state(ComponentA);
6+
let elem = $state.frozen();
7+
8+
$effect(() => {
9+
console.log(elem);
10+
});
11+
</script>
12+
13+
<button
14+
onclick={() => {
15+
type = ComponentA;
16+
}}>a</button
17+
>
18+
<button
19+
onclick={() => {
20+
type = ComponentB;
21+
}}>b</button
22+
>
23+
24+
<svelte:component this={type} bind:this={elem}>Content</svelte:component>

packages/svelte/tests/snapshot/samples/bind-component-snippet/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ export default function Bind_component_snippet($$anchor) {
3030

3131
$.template_effect(() => $.set_text(text, ` value: ${$.get(value) ?? ""}`));
3232
$.append($$anchor, fragment_1);
33+
return {};
3334
}

packages/svelte/tests/snapshot/samples/bind-this/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ import * as $ from "svelte/internal/client";
33

44
export default function Bind_this($$anchor) {
55
$.bind_this(Foo($$anchor, { $$legacy: true }), ($$value) => foo = $$value, () => foo);
6+
return {};
67
}

packages/svelte/tests/snapshot/samples/dynamic-attributes-casing/_expected/client/main.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ export default function Main($$anchor) {
3030
});
3131

3232
$.append($$anchor, fragment);
33+
return {};
3334
}

packages/svelte/tests/snapshot/samples/each-string-template/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ export default function Each_string_template($$anchor) {
1313
});
1414

1515
$.append($$anchor, fragment);
16+
return {};
1617
}

packages/svelte/tests/snapshot/samples/function-prop-no-getter/_expected/client/index.svelte.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ export default function Function_prop_no_getter($$anchor) {
2222
},
2323
$$slots: { default: true }
2424
});
25+
26+
return {};
2527
}

packages/svelte/tests/snapshot/samples/hello-world/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ export default function Hello_world($$anchor) {
77
var h1 = root();
88

99
$.append($$anchor, h1);
10+
return {};
1011
}

packages/svelte/tests/snapshot/samples/hmr/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ function Hmr($$anchor) {
77
var h1 = root();
88

99
$.append($$anchor, h1);
10+
return {};
1011
}
1112

1213
if (import.meta.hot) {

packages/svelte/tests/snapshot/samples/state-proxy-literal/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export default function State_proxy_literal($$anchor) {
2828
$.bind_value(input, () => $.get(str), ($$value) => $.set(str, $$value));
2929
$.bind_value(input_1, () => $.get(tpl), ($$value) => $.set(tpl, $$value));
3030
$.append($$anchor, fragment);
31+
return {};
3132
}
3233

3334
$.delegate(["click"]);

packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export default function Svelte_element($$anchor, $$props) {
88

99
$.element(node, tag, false);
1010
$.append($$anchor, fragment);
11+
return {};
1112
}

0 commit comments

Comments
 (0)