Open adiguba opened 2 hours ago
I make a small and quick PoC here for slots : https://adiguba-svelte-5-test-git-legacy-runes-adigubas-projects.vercel.app/ Source here : https://github.com/adiguba/svelte/tree/legacy-runes
There are some works to do (more checks, adding some warnings/errors, events, SRR...), but it works for slots on client side.
Example : REPL with 3 components :
Svelte4Component is a component that use the Svelte 4 syntax (<slot/>
).
Logically it only works with slots
Svelte5Component is the same component rewriten using the Svelte 5 syntax ({@render}
).
Now it's work with snippets... but not with slots.
This makes sense since it's theoretically a new component, so no reason to use it with slots.
Svelte5Legacy is the same component with Svelte 5 syntax, but which use $legacy() to describe the slots it should support. It's work with snippets, but slots are also supported.
Note that there is no specific API in Svelte5Legacy. It's just the same Svelte5Component with a $legacy() rune that describe the slots he accept.
The day slots are no longer supported, the $legacy rune could be deprecated and ignored...
Describe the problem
Svelte 5 remains compatible with Svelte 4 components by allowing the use of old syntaxes (slots, on:event directive). That's fine because it's will not break existing code, and this does not force a full migration which could be complex on large projects.
But there a catch : as soon as a Svelte 4 component is migrated to a Svelte 5 syntax, all files that use it must also be migrated to the new syntax :
on:event
directive may be broken (depending on how it is managed within the component)This is a breaking change that will force users of the component to migrate their own code, and which could push developers not to migrate their libraries...
I think it should be possible to migrate a Svelte 4 component to Svelte 5 syntax, while maintaining backward compatibility with existing code.
Slots
The default slot is managed properly, but they are some use-cases that can be problematic and break compatibility :
<slot name="header" />
should be converted into{@render header?.()}
. But any use of<div slot="header">...</div>
will be completely ignored !<slot prop1={value1} prop2={value2}/>
should be converted into{@render children?.(value1, value2)}
. But any code that use<Component let:prop1 let:prop2>
will now throw an error. In addition, thelet:
directive are managed differently from snippet parameters, and it should be translated.<slot name="info"/>
may have a conflict name with an existing props with the same name. So we may opt to a different name for the snippet, witch cause a breaking change.We can even have both, like
<slot name="footer" {copyright} {year}/>
that need to translate parameters and use a different name.Events
For events, I see 2 use-cases that might cause problems :
Migrating event's forwarding with
on:click
Currently event's forwarding is handled via a legacybubble()
function, but :on:click
but notonclick
...Migrating events dispatched via
createEventDispatcher()
Currently this would only support theon:event={fn}
directive, but not theonevent={fn}
. This must be rewritten to adopt Svelte 5 syntax.Describe the proposed solution
It would be great to be able to write these components with Svelte 5 syntax (snippets and onevent handlers), while maintaining compatibility with existing code that might use the new syntax.
I think the solution could be through metadata, which would indicate how to make the transition between the old syntax and the new one. Maybe by using a $legacy runes?
This rune will contains two information for each
slot
Exemple :
How would this work?
When the component is initialized, the
props
will be filled with the data from$$props
and$$events
according to the rules defined in these metadata. So the component could use Svelte 5 syntax internally, however it is used.In the same way,
createEventDispatcher()
should use this metadata in order to use props instead of $$events. So something like this :should be equivalent to :
Importance
nice to have