Skip to content
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

Slot forwarding causes recursion svelte-5 migration #14090

Closed
machycek opened this issue Nov 1, 2024 · 5 comments · Fixed by #14127
Closed

Slot forwarding causes recursion svelte-5 migration #14090

machycek opened this issue Nov 1, 2024 · 5 comments · Fixed by #14127
Labels

Comments

@machycek
Copy link

machycek commented Nov 1, 2024

Describe the bug

When you have a simple component that is forwarding a slot in Svelte 4 and migrate to Svelte 5 it doesn't work correctly. It causes infinite recursion where snippet is calling itself.

Reproduction

https://svelte.dev/playground/hello-world?version=5.1.9#H4sIAAAAAAAAE23LsQrCMBSF4VcJZ1IIdg-x4KaDT9A4pOYKhWsSmlu1lL67ZCg4OJ6P8y-I_kkwOBNzUu80clA7CoNQ2EPjMTAVmG6BzLn-KkBv1SnnQ3kRS7XeF_rn9xSFohQY2Ot8iXmS1kUntnASVYujA_ue2EFV-5lN66JttgoaQh-BkXGi9bZ-Ad0Pq9C-AAAA this is Svelte 4 code and click on migration it produces following https://svelte.dev/playground/hello-world?version=5.1.9#H4sIAAAAAAAAE22OzUrEQBCEX6VphU1CSO4x6nrTgyh43OwhP70QmZ1pZnrVMMy7y-wkePHUUNX1VXnU_ZmwwWdSysC3sWqCjKZZaMqxxNOsyGFz8CgLx78oYLmlnpgr90VKojb0jv7TR6OFtDhssHWjnVkeOt1JXRTxQAH7yJ7oBP5t-KRRArxbw25z2RomKwv4-czGSrZL6F1efeiZmSTAQfUDqWOK1J1eCxIa_JUXkiOKBDxcAxDgHm5jgcvyu0639d9A3b4uL5ovaa2_cakrBbM8RLUTv7ekJ7JJfqxWw9fre4jQDYQlCv0INmIvFI7hF8iH_MR-AQAA

Logs

No response

System Info

System:
    OS: macOS 14.6.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 9.94 GB / 64.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    Yarn: 1.22.21 - /usr/local/bin/yarn
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    Watchman: 2024.03.25.00 - /usr/local/bin/watchman
  Browsers:
    Brave Browser: 107.1.45.133
    Chrome: 130.0.6723.92
    Safari: 17.6
  npmPackages:
    svelte: ^5.0.0 => 5.1.3

Severity

blocking an upgrade

@paoloricciuti
Copy link
Member

We definitely shouldn't do this but unfortunately we can't really migrate this if the name of the slot in and out are the same. But we should bail and add a migration task

@brunnerh
Copy link
Member

brunnerh commented Nov 1, 2024

The snippet could be deconflicted via prop rename, e.g.

<script>
	// ...

	let { label: label2 } = $props();
</script>

<MyInput>
	{#snippet label()}
		{@render label2?.()}
	{/snippet}
</MyInput>

or

{#snippet label2()}
	{@render label?.()}
{/snippet}
<MyInput label={label2} /> <!-- will not work if MyInput is still using <slot> -->

(Maybe still annotate so a better name can be picked.)

@paoloricciuti
Copy link
Member

The snippet could be deconflicted via prop rename, e.g.

<script>
	// ...

	let { label: label2 } = $props();
</script>

<MyInput>
	{#snippet label()}
		{@render label2?.()}
	{/snippet}
</MyInput>

or

{#snippet label2()}
	{@render label?.()}
{/snippet}
<MyInput label={label2} /> <!-- will not work if MyInput is still using <slot> -->

(Maybe still annotate so a better name can be picked.)

Oh yeah you are right... I'll checkout later to see what we can do

@paoloricciuti
Copy link
Member

So i started implementing this and as usual is far more complex than expected 😄

Firstly we can't really rename the prop because if you use the same slot in another place or if you use $$slots those are transformed separately and previously. Eg

<slot name="label" />
<MyComponent>
    <slot name="label" slot="label" />
</MyComponent>

in this case the first slot can be converted without issues and the second one would need a rename. I was almost about to throw a migration error when i realised we can in-fact do something. Instead of migrating the slot name we can just rename it locally with @const so the above code could be migrated to

<script>
    let { label } = $props();
</script>

{@render label?.()}
<MyComponent>
    {@const label_render = label}
    {#snippet label()}
        {@render label_render?.()}
    {/snippet}
</MyComponent>

however i later realised that the problem is not just with slot forwarding...is whenever you use a slot withing an element that is a slotted element. For instance this is a problem too

<slot name="label" />
<MyComponent>
    <div slot="label">
        <slot name="label" />
    </div>
</MyComponent>

and to add a tiny bit of complexity in theory you can go as deep as you want and you can have multiple slotted content

<slot name="label" />
<MyInput>
    <div slot="label"> <!-- this is a problem -->
        <MyComponent>
            <div slot="label"> <!-- this is a problem too-->
                <slot name="label" />
            </div>
        </MyComponent>
    </div>
</MyInput>

however i just realized i think i can add a global derived...let's see.

@paoloricciuti
Copy link
Member

Ok it worked! 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants