svelte icon indicating copy to clipboard operation
svelte copied to clipboard

try block, like error boundary

Open tanhauhau opened this issue 5 years ago • 16 comments

Is your feature request related to a problem? Please describe.

I wonder would it possible to have a {#try} logic block, such that anything goes inside, if error would be handled in the {:catch} block, eg:

{#try}
   <Component />
{:catch}
   <div>Fallback uI </div>
{/try}

if an error thrown during init / update in <Component />, then will see the Fallback UI instead.

Describe the solution you'd like A clear and concise description of what you want to happen.

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

How important is this feature to you? Note: the more honest and specific you are here the more we will take you seriously.

Additional context Add any other context or screenshots about the feature request here.

tanhauhau avatar Oct 18 '19 09:10 tanhauhau

Good idea.

Maybe something like this would benefit even more, depending on the error getting thrown. So basically like a switch statement for catching errors.

<script>
import { GraphQLError } from 'graphql';
</script>


{#try}
   <Component />
{:catch GraphQLError}
	<div></div>
{:catch TypeError}
   <div></div>
{:catch}
   <div>Default fallback ui </div>
{/try}

marcus-sa avatar Oct 18 '19 09:10 marcus-sa

Can see this being useful especially when including components from 3rd parties.

MintyMods avatar Oct 18 '19 11:10 MintyMods

This has been brought up before, but I don't think there's a clear way that we could have this work. I don't think it would be too difficult to have handlers for exceptions that synchronously occur as part of an operation on the child component (instantiating it, or updating props for example), but there's not a good way to handle other exceptions that happen during the life of the component. The component would have to emit events (or do something else equivalent to that), but only when it appears inside a {#try}. (In other cases, it should continue to throw exceptions as it currently does.) Every compiled component would have to support being run inside of a {#try}, regardless of whether it ever actually is, because at compile time we can't tell that. This would be a burden on every component whether this feature was being used or not.

Conduitry avatar Oct 18 '19 18:10 Conduitry

Yup, I just realised there's a RFC https://github.com/sveltejs/rfcs/pull/11 that brought up the exact same issue.

Every compiled component would have to support being run inside of a {#try}

That's how context works as well. Every component has to know which context it is currently mounted into.

I would like to propose a similar mechanism, where the error boundary of a component is assignes when mounted, just like context, (or it could be a special context key 🤔) So at the point of error, there's no bubbling up of errors, but rather catching it directly to the preassigned error boundaries

tanhauhau avatar Nov 01 '19 01:11 tanhauhau

There was some discussion about this in the discord #future channel the other day, an I thought I'd jot down some notes here for posterity.

@halfnelson had created this error boundary proof-of-concept: https://svelte.dev/repl/006facb65ece4f808cd733e838783228?version=3.22.2

If we imagine some sort of event based API, then maybe extending the slot syntax would make more sense?

<script>
  let error;
</script>

{#if error}
  <p>Error: {error}</p>
{:else}
  <slot on:error={({ detail }) => {
    error = detail.message;
    logMyErrorSomewhere(detail);
  }} />
{/if}

jonatansberg avatar May 11 '20 14:05 jonatansberg

I improved a bit on the REPL linked above, adding support for SSR and logging: https://svelte.dev/repl/9d44bbcf30444cd08cca6b85f07f2e2a?version=3.29.4

jonatansberg avatar Nov 05 '20 14:11 jonatansberg

Has there been any progress on this? Or an alternate way to handle such errors? I have JSON files containing data for my HTML pages, which contain keys like title, summary, blockquote etc. This file is stored in a variable called post and added into the page as follows:

<main>
	<div class="container max-w-5xl mt-6 px-6">
		<div class="pb-5 mb-5 border-b border-gray-100">
			<h1 class="font-bold text-5xl">{post.title}</h1>
			<h2>{post.summary}</h2>
		</div>
		<article class="prose lg:prose-xl my-4 mx-auto">
		{#each post.text as text}
			<p>{text.value}</p>
		{/each}
		</article>
		<div class="flex flex-wrap">
			{#each post.images as image}
				<div class="w-full ">
					<img src="{image.value.src}" alt="{image.value.alt}" class="w-full h-auto" />
				</div>
			{/each}
		</div>
	</div>
</main>

Now some posts might have a key while others may not. Currently, Svelte throws an error which stops my build process if any file is missing any key.

It would be good to 'try to look for this key, if it exists then add it otherwise just move on' kind of logic. I could implement an if-else block for each key but is there a more elegant way to handle this?

thedivtagguy avatar Jan 02 '22 17:01 thedivtagguy

Solved my problem by using optional chaining. {post?.title} and so on.

thedivtagguy avatar Jan 03 '22 12:01 thedivtagguy

@YamiOdymel, this feature request goes beyond simple error handling is more along the lines of React's Error Boundaries.

mrcasual avatar Feb 16 '22 17:02 mrcasual

Hello, everyone. I am currently working on an RFC that can solve this issue.

ghost avatar Nov 12 '22 22:11 ghost

Here's the RFC: sveltejs/rfcs#69

ghost avatar Nov 13 '22 19:11 ghost

This seems like an RFC for tag extensions, which allows any kind of tags, but doesn't by itself add try/catch. I'd have to "import" that as custom syntax extension. If I understood correctly.

I personally would prefer exception/error handling to be a fundamental part of Svelte.

This concerns a) errors when creating the sub-components b) errors thrown from b.1.) event handlers b.2.) $: reactivity statements, b.3.) {} expressions in the markup b.4.) onMount()/onDestroy() b.5.) and similar entry points, and c) errors thrown up explicitly by JS code within the component.

Right now, a naive app implementation that follows the code patterns in the tutorial will not handle any errors. And handling all error properly requires either a lot of try/catch/emit boiler plate, or a custom error handling infrastructure.

benbucksch avatar Dec 16 '22 00:12 benbucksch

Any updates due to Svelte5?

emil14 avatar Feb 23 '24 05:02 emil14

Wouldn't having a hook to deal with errors be better than handling errors in the markup? IMHO it'll make it easy to manipulate the errors.

<script>
import { onError } from "svelte";
import { logger } from "analytics";

let error;

onError((_error) => {
    error = _error;
    logger.error(_error);
})
</script>

{#if error}
   <FallbackUI />
{:else}
   <Component />
{/if}

sifat-at-work avatar Jun 25 '24 05:06 sifat-at-work

Yes, indeed, I'd like that. This is great. Simple and meers all requirements.

Component level is the right granularity. (If I want to catch something more specific, I can use try/catch.)

This could catch all the other error classes, like exceptions in $: statements, in markup {} code, in the initial execution of the JS section code, and many other error classes.

Errors in sub-components should bubble up and be caught by the onError() of the calling component. This would not force me to add an onError() in every single component. Bubbling would also allow to show errors in a custom UI for a specific bigger component, including errors in generic sub-components. The error UI would depend on the enclosing component, which is what we need for complex user-friendly apps.

benbucksch avatar Jun 25 '24 09:06 benbucksch