mirror of https://github.com/sveltejs/svelte
feat: make `<svelte:component>` unnecessary in runes mode (#12646)
* feat: make `<svelte:component>` unnecessary in runes mode In Svelte 4, writing `<Component />` meant that the component instance is static. If you made the variable `Component` a reactive state variable and updated the component value, the component would not be reinstantiated with the new value - you had to use `<svelte:component>` for that. One reason was that having a dynamic component was more overhead, which is no longer the case in Svelte 5. We can therefore reduce the potential API surface area (by maybe deprecating `<svelte:component>` in the future) by allowing Svelte to recognize when a component variable is potentially dynamic. It turned out that this was already mostly the case. This PR fixes one case where it wasn't, and fixes another where this was wrongfully applied in legacy mode. * we already have this function * add interactive demos * changeset --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/12667/head
parent
00e8ebde1d
commit
8be7dd558b
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
feat: make `<svelte:component>` unnecessary in runes mode
|
@ -0,0 +1 @@
|
||||
Component1
|
@ -0,0 +1 @@
|
||||
Component2
|
@ -0,0 +1,14 @@
|
||||
import { test } from '../../test';
|
||||
import { flushSync } from 'svelte';
|
||||
|
||||
export default test({
|
||||
html: '<button>switch</button> Component1 Component1',
|
||||
async test({ assert, target }) {
|
||||
const btn = target.querySelector('button');
|
||||
|
||||
btn?.click();
|
||||
flushSync();
|
||||
|
||||
assert.htmlEqual(target.innerHTML, '<button>switch</button> Component2 Component2');
|
||||
}
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
<script>
|
||||
import Component1 from './Component1.svelte';
|
||||
import Component2 from './Component2.svelte';
|
||||
|
||||
let Component = $state(Component1);
|
||||
let Object = {
|
||||
get component() {
|
||||
return Component;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<button onclick={() => (Component = Component2)}>switch</button>
|
||||
|
||||
<Component />
|
||||
<Object.component />
|
@ -1,3 +0,0 @@
|
||||
import { test } from '../../test';
|
||||
|
||||
export default test({ skip: true });
|
@ -1,30 +0,0 @@
|
||||
<script>
|
||||
import A from './A.svelte';
|
||||
import B from './B.svelte';
|
||||
|
||||
let Let = A;
|
||||
function update() {
|
||||
Let = B;
|
||||
}
|
||||
|
||||
export let ExportLet = B;
|
||||
|
||||
$: Reactive = random() ? A : B;
|
||||
</script>
|
||||
|
||||
<Let />
|
||||
<ExportLet />
|
||||
<Reactive />
|
||||
<svelte:component this={Let} />
|
||||
|
||||
<!-- Here, we test to see if svelte-ignore works with reactive-component -->
|
||||
<!-- svelte-ignore reactive_component -->
|
||||
<Let />
|
||||
<div>
|
||||
<!-- svelte-ignore reactive_component -->
|
||||
<ExportLet />
|
||||
<div>
|
||||
<!-- svelte-ignore reactive_component -->
|
||||
<Reactive />
|
||||
</div>
|
||||
</div>
|
@ -1,38 +0,0 @@
|
||||
[
|
||||
{
|
||||
"code": "reactive_component",
|
||||
"message": "<Let/> will not be reactive if Let changes. Use <svelte:component this={Let}/> if you want this reactivity.",
|
||||
"end": {
|
||||
"column": 7,
|
||||
"line": 15
|
||||
},
|
||||
"start": {
|
||||
"column": 0,
|
||||
"line": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"message": "<ExportLet/> will not be reactive if ExportLet changes. Use <svelte:component this={ExportLet}/> if you want this reactivity.",
|
||||
"code": "reactive_component",
|
||||
"end": {
|
||||
"column": 13,
|
||||
"line": 16
|
||||
},
|
||||
"start": {
|
||||
"column": 0,
|
||||
"line": 16
|
||||
}
|
||||
},
|
||||
{
|
||||
"message": "<Reactive/> will not be reactive if Reactive changes. Use <svelte:component this={Reactive}/> if you want this reactivity.",
|
||||
"code": "reactive_component",
|
||||
"end": {
|
||||
"column": 12,
|
||||
"line": 17
|
||||
},
|
||||
"start": {
|
||||
"column": 0,
|
||||
"line": 17
|
||||
}
|
||||
}
|
||||
]
|
Loading…
Reference in new issue