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

Svelte 5: Incorrect Server Output for $effect.root #12322

Closed
abdel-17 opened this issue Jul 6, 2024 · 15 comments · Fixed by #12332
Closed

Svelte 5: Incorrect Server Output for $effect.root #12322

abdel-17 opened this issue Jul 6, 2024 · 15 comments · Fixed by #12332
Labels
Milestone

Comments

@abdel-17
Copy link

abdel-17 commented Jul 6, 2024

Describe the bug

On the server, $effect.root should return a noop function, but it returns undefined because the function is immediately invoked.

Reproduction

https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAEz2N0QrDIAxFf0XCHiyM9d21hX3HuodiIwhWRWNhiP_eyGBcyOWE3NwKxjrMoN4V_HYgKHjFCHegb-yQT3SEzDmUpPtmyjrZSMvqV9LBZxLa4eZLFLO4oTGo6ZFCICkHMS-i9jsWzzY82XrsF5Cdp_H_j1uOsFtjcQdFqWD7tAuiqNgToAAAAA==

Logs

No response

System Info

Safari 17.4 iOS

Severity

annoyance

@Kapsonfire-DE
Copy link
Contributor

can confirm it, behaviour changed in 175. 174 still returns a function

@dummdidumm dummdidumm added this to the 5.0 milestone Jul 6, 2024
@dummdidumm
Copy link
Member

The question is whether effect.root should just return a noop function, or if it should immediately invoke the function to execute stuff outside of effects inside, and then return the provided cleanup function and as backup a noop function.

@abdel-17
Copy link
Author

abdel-17 commented Jul 6, 2024

The question is whether effect.root should just return a noop function, or if it should immediately invoke the function to execute stuff outside of effects inside, and then return the provided cleanup function and as backup a noop function.

My intuition says keep anything related to $effect client only. It would be strange for $effect.root to be the only fn that executes on the server.

@paoloricciuti
Copy link
Member

The question is whether effect.root should just return a noop function, or if it should immediately invoke the function to execute stuff outside of effects inside, and then return the provided cleanup function and as backup a noop function.

I wanted to work on this but i actually have the same question. Can it make sense to have effect.root run on the server even if the effects inside it doesn't? Not running the function is currently a breaking change. Should i open the pr and then we can think about it?

@abdel-17
Copy link
Author

abdel-17 commented Jul 7, 2024

Can it make sense to have effect.root run on the server even if the effects inside it doesn't? Not running the function is currently a breaking change.

Are you sure about this? It seems $effect.root is currently striped entirely from the server output.

@paoloricciuti
Copy link
Member

Can it make sense to have effect.root run on the server even if the effects inside it doesn't? Not running the function is currently a breaking change.

Are you sure about this? It seems $effect.root is currently striped entirely from the server output.

<script>
	const cleanup = $effect.root(() => {
		console.log("this should run")
	});

	cleanup();
</script>

this generates the following code

import * as $ from "svelte/internal/server";

export default function App($$payload) {
	const cleanup = (() => {
		console.log("this should run");
	})();

	cleanup();
}

so it should be executed on the server.

@abdel-17
Copy link
Author

abdel-17 commented Jul 7, 2024

It's actually inconsistent. It gets stripped when you don't capture the return value.

$effect.root(() => {
	console.log("1");
});

const cleanup = $effect.root(() => {
	console.log("2");
});

// generates
const cleanup = (() => {
	console.log("2");
})();

@paoloricciuti
Copy link
Member

Uh then I guess the best thing is probably just change effect.root with a noop if it gets captured. The fact that is stripped shows that it's not meant to be executed

@Kapsonfire-DE
Copy link
Contributor

Kapsonfire-DE commented Jul 7, 2024

the docs saying, $effects run on mount (pre before update), therefor it should never run on serverside

To run side-effects when the component is mounted to the DOM, and when values change, we can use the $effect rune (demo):

IMO
therefore $effect.root should never run on SSR only on hydration

The fix for return should be a no-brainer

 if (rune === '$effect.root') {
            const args = /** @type {import('estree').Expression[]} */ (
                node.arguments.map((arg) => context.visit(arg))
            );
            // Just call the function directly
            return b.call(args[0])??(()=>{});
        }

@paoloricciuti
Copy link
Member

the docs saying, $effects run on mount (pre before update), therefor it should never run on serverside

To run side-effects when the component is mounted to the DOM, and when values change, we can use the $effect rune (demo):

IMO therefore $effect.root should never run on SSR only on hydration

The fix for return should be a no-brainer

 if (rune === '$effect.root') {
            const args = /** @type {import('estree').Expression[]} */ (
                node.arguments.map((arg) => context.visit(arg))
            );
            // Just call the function directly
            return b.call(args[0])??(()=>{});
        }

effects and effect.root are two different things but I do agree that it's probably not meant to run on the client.

The fix is a tad different because you want to return the expression that represents a noop and not the noop itself, also at this point is not even worth visiting the node on the server, you just want to completely remove effect.root if the return value is not assigned or substitute it with a noop of it is.

@trueadm
Copy link
Contributor

trueadm commented Jul 7, 2024

We could make $effect.root not run on the server, but technically it always has, it's just the effects themselves that don't. The problem here is that if you don't return your own cleanup function, then maybe we should provide an empty function for that case.

@trueadm trueadm self-assigned this Jul 7, 2024
@trueadm trueadm added the bug label Jul 7, 2024
@paoloricciuti
Copy link
Member

We could make $effect.root not run on the server, but technically it always has, it's just the effects themselves that don't. The problem here is that if you don't return your own cleanup function, then maybe we should provide an empty function for that case.

Yeah the idea was to just provide a noop for that. Also #12322 (comment) suggest it was not run if the user did not assigned the return value.

Also will you work on this? I was planning to work on this in 20-ish minutes but if you are planning to work on it now up to you.

@trueadm trueadm removed their assignment Jul 7, 2024
dummdidumm added a commit that referenced this issue Jul 7, 2024
- should return a callback function, always (which means it may need a fallback noop function)
- should invoke the cleanup function on component destroy in SSR for effect root directly connected to a component

fixes #12322
@paoloricciuti
Copy link
Member

paoloricciuti commented Jul 7, 2024

After talking with Dominic he confirmed that effect root should actually run on the server and the fact that it's eliminated is actually a bug...will fix both here

dummdidumm added a commit that referenced this issue Jul 7, 2024
Ignore the contents of the effect root, just return a noop where necessary

fixes #12322
dummdidumm added a commit that referenced this issue Jul 8, 2024
Ignore the contents of the effect root, just return a noop where necessary

fixes #12322
@Kapsonfire-DE
Copy link
Contributor

can you make clear in the preview docs, that root behaves different and also meant to be run on server side?

@Antonio-Bennett
Copy link

@Kapsonfire-DE I think they ended up going with the PR that ignores it on the server so it behaves like the other runes? Correct me if I’m wrong

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