svelte: Unable to use return in reactive expression
When using a return statement in a reactive expression/block an error is thrown:
'return' outside of function (L:C)
Since the reactive expression contents is wrapper in a function at compile time, this shouldn’t cause any syntax errors at runtime.
I imagine this will require changes to the svelte compiler and also the eslint plugin rules.
See a simple repro here:
https://svelte.dev/repl/8ca16f5088c34dd89574a064868d9b4d?version=3.4.1
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 2
- Comments: 20 (16 by maintainers)
Commits related to this issue
- preserve `$:` label in reactive blocks in SSR mode (#2828) — committed to Conduitry/svelte by Conduitry 5 years ago
- preserve `$:` label in reactive blocks in SSR mode (#2828) — committed to Conduitry/svelte by Conduitry 5 years ago
- preserve `$:` label in reactive blocks in SSR mode (#2828) (#3469) — committed to sveltejs/svelte by Conduitry 5 years ago
Something just occurred to me that maybe should be obvious.
Svelte is repurposing labeled blocks, by deleting the actual label and moving the block into a function. The only reason someone might expect
returnto work in this context is because they are looking at the compiled output, which is inside a function.However, a real labeled block already has a way to exit early. In fact, it’s pretty much the only “feature” a real labeled block has:
That’s valid JS, but if you put that into the Svelte compiler, it just looks at you funny. It happily accepts the following though:
…but of course doesn’t make it reactive.
So, if early exits are even a concern, my suggestion would be to implement it by adding support for labeled breaks. That would bring Svelte semantically closer to “real” JS in its handling of labeled blocks, rather than continue to deviate. It also solves the issue with returns and multiple reactive statements.
I’d even imagine it would be quite straightforward to implement. The compiler would simply not delete the label when it moves the reactive declaration into the update function.
Example change:
Labels not being treated as a function by the compiler comes back to bite me a lot since I prefer to use early-outs whenever possible.
This case can obviously become a simple
if/else, but they’re not always that simple. The inability to usereturnorcontinueor some other form of “stop executing this block” is a fairly frequent annoyance for me in v3.This isn’t pretty, but a workaround that you can do at the moment is to put a label statement in the reactive statement. It’s less code than an iife anyway. The REPL will let you get away with the following:
$: X: if (count >= 10) { alert('count is dangerously high!'); break X; count = 9; }This always bails out early. The count never gets set back to nine.
Yeah, I can see the appeal, but I would personally rather opt for using an IIFE than start treating blocks as functions.
It’s not valid JavaScript so it would break prettier and other tools. 🤔
I think in my ideal world the svelte compiler would be able to see that pattern and remove it to keep the code streamlined, paying the cost for IIFE every time a reactive statement runs isn’t something I’m super comfortable with.