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>
pull/12308/head
Paolo Ricciuti 6 months ago committed by GitHub
parent 831552f4b3
commit e42bb61296
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: ensure component always returns an object

@ -339,6 +339,9 @@ export function client_component(source, analysis, options) {
? b.return(b.call('$.pop', b.object(component_returned_object)))
: b.stmt(b.call('$.pop'))
);
} else {
// Always return an object, so that `bind:this` on this component will not be falsy
component_block.body.push(b.return(b.object(component_returned_object)));
}
if (analysis.uses_rest_props) {

@ -0,0 +1,5 @@
<script>
export const a = {};
</script>
<div>a</div>

@ -0,0 +1,26 @@
import { flushSync } from 'svelte';
import { test } from '../../test';
export default test({
html: `<button>a</button><button>b</button><div>a</div>`,
compileOptions: {
dev: false
},
async test({ assert, target, logs, ok }) {
const [btn1, btn2] = target.querySelectorAll('button');
flushSync(() => {
btn2.click();
});
assert.htmlEqual(target.innerHTML, `<button>a</button><button>b</button><div>b</div>`);
flushSync(() => {
btn1.click();
});
assert.htmlEqual(target.innerHTML, `<button>a</button><button>b</button><div>a</div>`);
assert.deepEqual(logs, [{ a: {} }, {}, { a: {} }]);
}
});

@ -0,0 +1,24 @@
<script>
import ComponentA from './ComponentA.svelte';
import ComponentB from './ComponentB.svelte';
let type = $state(ComponentA);
let elem = $state.frozen();
$effect(() => {
console.log(elem);
});
</script>
<button
onclick={() => {
type = ComponentA;
}}>a</button
>
<button
onclick={() => {
type = ComponentB;
}}>b</button
>
<svelte:component this={type} bind:this={elem}>Content</svelte:component>

@ -30,4 +30,5 @@ export default function Bind_component_snippet($$anchor) {
$.template_effect(() => $.set_text(text, ` value: ${$.get(value) ?? ""}`));
$.append($$anchor, fragment_1);
return {};
}

@ -3,4 +3,5 @@ import * as $ from "svelte/internal/client";
export default function Bind_this($$anchor) {
$.bind_this(Foo($$anchor, { $$legacy: true }), ($$value) => foo = $$value, () => foo);
return {};
}

@ -30,4 +30,5 @@ export default function Main($$anchor) {
});
$.append($$anchor, fragment);
return {};
}

@ -13,4 +13,5 @@ export default function Each_string_template($$anchor) {
});
$.append($$anchor, fragment);
return {};
}

@ -22,4 +22,6 @@ export default function Function_prop_no_getter($$anchor) {
},
$$slots: { default: true }
});
return {};
}

@ -7,4 +7,5 @@ export default function Hello_world($$anchor) {
var h1 = root();
$.append($$anchor, h1);
return {};
}

@ -7,6 +7,7 @@ function Hmr($$anchor) {
var h1 = root();
$.append($$anchor, h1);
return {};
}
if (import.meta.hot) {

@ -28,6 +28,7 @@ export default function State_proxy_literal($$anchor) {
$.bind_value(input, () => $.get(str), ($$value) => $.set(str, $$value));
$.bind_value(input_1, () => $.get(tpl), ($$value) => $.set(tpl, $$value));
$.append($$anchor, fragment);
return {};
}
$.delegate(["click"]);

@ -8,4 +8,5 @@ export default function Svelte_element($$anchor, $$props) {
$.element(node, tag, false);
$.append($$anchor, fragment);
return {};
}
Loading…
Cancel
Save