-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
feat: make <svelte:component>
unnecessary in runes mode
#12646
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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.
🦋 Changeset detectedLatest commit: ca2e825 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Do we want to go so far as to deprecate <svelte:component this={condition ? A : B}> |
I'm honestly not sure. I wouldn't mind deprecating it - examples like yours are probably rare, and writing |
Deprecating is fine. I just searched our code base and found 3 places and all of them will look more elegant with the new approach. |
So does this mean I can now: <script>
let DynamicComponent = $derived(value > 10 ? A : B);
</script>
<DynamicComponent /> |
Yes, |
Does this have to be wrapped in state? Because when I try this in one of my components it works perfectly if I define
If I change it to not be self closing I still have it never being used. might be a tooling issue but calling it out. |
I can open a second issue but I'm not sure we are covering the following scenario where we iterate over an array to display a component:
With this change, what's the best way to handle this? |
How is this supposed to work in an I have somethin similar to the below. REPL <script>
import IconA from './IconA.svelte'
import IconB from './IconB.svelte'
let icons = {
a: IconA,
b: IconB,
}
let things = [
{text: "A", icon: "a"},
{text: "B", icon: "b"},
]
let MyIcon = $derived(icons['a'])
</script>
<div><i>$derived</i> component <MyIcon /> - OK</div>
{#each things as thing}
<div><i>svelte:component</i> <svelte:component this={icons[thing.icon]} /></div>
<!-- <icons[thing.icon] /> NOPE -->
{/each} (I seem to have typed this at the same time as @niemyjski) |
Take a look at my comment in the related issue You can make it work just by uppercasing |
Thanks @paoloricciuti In my example I tried with these changes;
|
Oh missed that...then you can do this {#each things as thing}
{@const Icon = icons[thing.icon]}
<div><i>svelte:component</i> <Icon /></div>
<!-- <icons[thing.icon] /> NOPE -->
{/each} |
Thanks again @paoloricciuti I was too invested in "svelte 5 shiny" to get back to the basics! |
|
Wow, I don't know why the hell Svelte is becoming more verbose. |
This is the single edge case we're svelte:component would be less verbose. For all the rest it becomes less verbose and if you want you can still use it with the ignore. Sometimes you need to loose some to gain some. |
Just an example:
following code:
gets replace with:
|
|
||
<!-- these are equivalent --> | ||
<Thing /> | ||
<svelte:component this={Thing} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got confused by this initially and suggest that this should be a comment as to highlight that it is no longer needed. Adds more clarity.
How do we handle typing with components that are from packages that have not been updated to Svelte 5 yet? E.g. The following works but TypeScript complains about Sun and Moon not being Components <script lang="ts">
import Moon from 'lucide-svelte/icons/moon'
import Sun from 'lucide-svelte/icons/sun'
import type { Component } from 'svelte'
</script>
{#snippet foo(Icon: Component)}
Here's a <Icon />
{/snippet}
<ul>
<li>{@render foo(Sun)}</li>
<li>{@render foo(Moon)}</li>
</ul>
|
Also accept the old |
Unfortunately that still doesn't work. TypeScript errors on both the usage of <script lang="ts">
import Moon from 'lucide-svelte/icons/moon'
import Sun from 'lucide-svelte/icons/sun'
import type { Component, SvelteComponent } from 'svelte'
</script>
{#snippet foo(Icon: Component | SvelteComponent)}
Here's a <Icon />
{/snippet}
<ul>
<li>{@render foo(Sun)}</li>
<li>{@render foo(Moon)}</li>
</ul>
|
Sorry, I meant |
That works. Thanks! |
In Svelte 4, writing
<Component />
meant that the component instance is static. If you made the variableComponent
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.Also fixes #12646
Before submitting the PR, please make sure you do the following
feat:
,fix:
,chore:
, ordocs:
.Tests and linting
pnpm test
and lint the project withpnpm lint