-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Feature suggestion: error handling API #1096
Comments
I also would love error handling so much. |
To fit w/ svelte v3 I think this should probably be just like the rest of the lifecycle hooks:
Internally this would do something like this:
And each component that imports
Where wrap is shared code that looks like this:
This is mostly a sketch here... |
I like this for two reasons:
Gets my vote. |
Here's the docs on Vue's implementation https://vuejs.org/v2/api/#errorCaptured |
This comment has been minimized.
This comment has been minimized.
@trenta3, let's not oversimplify here. Every feature requires a design, implementation, tests, and documentation. Even the implementation is bigger than just adding a try catch, you have to handle bubbling, adding event handlers, making any changes to parsers and code generators, writing the 'onError' function and all supporting code, etc. I'm very much I'm favor of this, but it's certainly not a done deal. Even the design is under specified at this time. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Writing a component like this would be nice:
only svelte:error renders if there are any errors |
@lastqubit I think the idea is to add error handling in component script code, rather than have a new svelte tag. The scope of a An |
@antony Without a svelte:error component everyone has to write the boilerplate code to display errors and that doesn't fit with sveltes strength of being user friendly. If you somehow can get the error object in the error component it's very elegant. Everyone has to handle errors, so to have a specialized component that's very easy to use is not a narrow scope in my opinion. svelte:error becomes a more user friendly and elegant version of ErrorBoundary in react. You can log like this:
Without my suggestion you have to wrap every component in an if statement(very ugly)
|
@lastqubit I feel that is very lazy error handling. Errors should be dealt with on a case by case basis, and only thrown to a global handler if there really is no way for the user to recover. Boilerplate is only boilerplate if it's the same everywhere, which it shouldn't be. Additionally, if you're writing a notification display in every single component, wrapped in a Here's how I'd deal with errors in my components:
and if I think this is too boilerplatey, I can export a handler from some
|
@antony My example is more like ErrorBoundary in react, where your entire component should become an error page on exceptions. Your code handles errors by notifications and doesn't really show the code for actually displaying errors as html. I see alot of value in a svelte:error component whose only purpose is to remove that extra ugly wrapping {#if} statement for displaying error pages. You can have both an onError and svelte:error and choose what fits your needs. |
@lastqubit I didn't want to include my entire notifications library in my example, but I use this: https://www.npmjs.com/package/@beyonk/svelte-notifications I'm not averse to both a component and a handler, however I feel that having both could cause some confusion as to who handles the error first? The code, or the view component? |
@antony The code handles first, and you get a chance to transform the error object. I don't know what syntax to use to get the error object in the component but it would be nice if you didn't have to declare it yourself in the script tag
|
I don't think there's a need for a {#if error}
<h1>An Error! {error.message}</h1>
<pre>
{error.stackTrace}
</pre>
{:else}
<slot></slot>
{/if}
<script>
import errorStore from './error-store.js'
const unsubscribe = errorStore.subscribe(value => {
if (!value) { return }
error = value
errorStore.set()
})
onDestroy(unsubscribe)
let error = null
</script> |
@antony That's like the example i wrote, and i think it's very ugly. It's annoying when frameworks are very elegant in demos and presentations but then that elegance disappear when you have to write real world code. Everything is trivial in react to, but when you constantly have to write way more ugly code than needed it becomes a mess pretty quickly. If i wanna write a simple image component that renders differently on exceptions i should write that code everytime instead of just adding svelte:error and render my error code in that? |
@lastqubit The example above would not be repeated at all, it would be a component: as a "boundary" style component: <ErrorBoundary>
<h1>Your other code</h1>
</ErrorBoundary> or as a simple error notification: <ErrorDisplay /> Roughly equivalent to your suggestion of An annoying thing about frameworks is when they get too opinonated, which is, in my view, a problem React has. |
@antony I don't understand why everyone should write their own error boundary component when svelte:error would be perfect. I don't understand why svelte:error would be opinionated and svelte:head for example is not. It's very easy to change title in react but i love svelte:head. It's very elegant and right away you get a perfect understanding of your component, svelte:error would continue that tradition instead of having to write that annoying boiler plate code that everyone who starts using svelte have to write.
is very elegant and right away you understand the component. The code variant is a mess in comparison. |
@lastqubit So, I think the issue is that it's not totally perfect. It doesn't define what should happen in parent components, it's not as flexible as With an Here I feel like I must re-iterate that the implementation of this is non-trivial... |
One last comment here:
Unfortunately the real world is tricky. Especially handling errors which can be for any one of an unlimited number of reasons. I don't think you'll find that the elegance has actually gone, though, just because a convenient piece of syntactic sugar is not present. Having a consistent and predictable pattern is key to the elegance. Maybe once the core |
Not having some sort of built in handler for errors is really painful, as I just discovered today. I have a After some digging, I found out that the culprit was this line: svelte/src/runtime/internal/scheduler.ts Line 17 in 1273f97
resolved_promise.then(flush);
When an error is thrown inside a Promise it looks like Firefox still calls That last piece with the websockets is probably outside svelte's purview, but if svelte had provided some sort of Ideally that same line above - and everywhere else svelte uses Promises like this - becomes something like |
This would be a very useful feature. |
Learning svelte I landed here looking for guidance on handling errors and think the In the mean time something in the REPL or tutorial about this would help newcomers like me. |
If at least one component has smallest unhandled error, the whole app will crash and users will not know what to do and developers will not know such an error occurred. Here is the code snippet of how I am using it at the moment: |
Important to note that the snippet https://svelte.dev/repl/c6dddc73cbdd4f81883add43f5e3aa25?version=3.18.2 will not work for all types of errors, and there's no way to get something like Sentry to be able to record all errors and/or show a proper error message for all errors, so your app just freezes and if its' your users experiencing the error you won't even know about it. You can't write cypress tests for business logic edge cases and browser incompatibilities you don't know about. |
Just make sure to call the original onunhandledrejection after you are done, otherwise we (Sentry) are not able to pick up the error. onMount(() => {
const originalUnhandledRejection = window.onunhandledrejection;
window.onunhandledrejection = (e) => {
console.log('we got exception, but the app has crashed', e);
// or do Sentry.captureException(e);
originalUnhandledRejection(e);
}
}) Another option is to do nothing at all and just call |
I think this would make a great RFC, if there is appetite. |
I've taken the initiative to start and implement the <script>
import { onError } from "svelte";
let a;
let b = {};
let error = false;
onError(() => {
error = true;
});
a.b; // Error is thrown here
b.c = true;
</script>
{#if error}
Caught
{/if}
{#if b.c}
Property `c` on `b` is true
{/if} In this case, would you expect the behavior to be in this case? Should the 'Caught' message show? A case can also be make for not mounting the component at all because it would make it clearer for the developer what is being shown after an error and what isn't but this also defeats the purpose a bit of having Just let me know any of your thoughts on this. |
@rster2002 Thoughts about this approach? <script>
import { onError } from "svelte";
import ErrorComponent from "./ErrorComponent.svelte";
let a;
let b = {};
onError(() => {
return {component: ErrorComponent, props: {}};
});
a.b; // Error is thrown here
b.c = true;
</script>
{#if b.c}
Property `c` on `b` is true
{/if} The onError return value will render when there is an error. <svelte:component this={component} {...props}/> To render the error component behind the scenes. Fewer amount of lines, easier to refactor and reuse |
Interesting approach. So this would basically replace the current component with the |
@rster2002 Yeah, i guess you could just show nothing then. Or maybe, there could be some default fallback ErrorComponent with some basic information about the error. |
@rster2002 I'm not sure if it is possible, but if you solved the error you could return this, to attempt again? Probably would give kinda weird syntax onError(() => {
if(solved){
return {component:"this", props: {}}
}
else{
return {component: ErrorComponent, props: {}};
}
}); |
It would probably be possible, but this would make it very easy to create infinite loops where the component fails initializing no matter what. |
@rster2002 Thought that would definitely complicate things haha :P |
while I like @eddpeterson https://svelte.dev/repl/c6dddc73cbdd4f81883add43f5e3aa25?version=3.18.2 approach to be better. It's vanilla JS, doesn't |
@basaran @rster2002 <script>
import ErrorComponent from "./ErrorComponent.svelte";
let a;
let b = {};
a.b; // Error is thrown here
b.c = true;
</script>
<svelte:error on:error={(error) => {}} let:error={error}>
<ErrorComponent statusCode={error.statusCode}/>
</svelte:error>
{#if b.c}
Property `c` on `b` is true
{/if} One idea is to ignore the error when returning false on the on:error Seems like this guy has the same idea: sveltejs/rfcs#46 (comment) |
I think it's worth mentioning that SvelteKit seems to be solving this problem one layer higher, with a separate |
I'm at a complete loss with this issue. We are preparing our svelte 3 application for a production release and encounter the following scenario:
^-- this works gangbusters, except... I noticed a scenario where a component on a particular page references a property we just removed from the session store (
...this appears to halt all execution and silently crashes the page, instead of redirecting the page route. I can see the errors in the console. I can fix this specific scenario easily with a
...however there is no way for me to prevent the next guy from breaking this with the next code change unless we exercise session expiration on every page when we regression test the app. See the problem? Note: We have no issues handling specific try catch scenarios that the code is anticipating. But there must be a way to implement a global error handler that I can wire up to my existing comprehensive error store + component for these kind of issues. I have tried Boundary and ErrorBoundary solutions as they have been floated in this thread, but none of those invoke the handler under the scenario described above when I tested them out. IMHO we need a solution analogous to a global-scoped exception filter in NestJS (https://docs.nestjs.com/exception-filters) - a safety net for unanticipated errors that we can hook into and handle in our own preferred way without halting client-side app execution. |
Just want to add an example demonstrating the issue here: https://svelte.dev/repl/990219d2c7a34ce59bd7697ff552ea8a?version=3.46.4 In short, |
Hey everyone, is there any progress on this? It is the last major feature I would need before shipping my app to production |
Errors can happen (at least) in the following places:
If I missed some error classes, please add them. For many of these error classes, the developer can manually add a try/catch, for each instance. However, for a large app, that can quickly become so cumbersome to not be realistic. And it also goes against the philosophy of Svelte of writing natural, concise code that expresses clearly what it does, not mechanical boilerplate. ("No boilerplate" is one of the Svelte mantras.) Just to quantify the magnitude of the problem: Our app currently has almost 800 JS, Java, C#, C++ and many other languages have exceptions, which bubble up errors the function stack and allow to catch and handle them on any level. We need the same on the UI level, to catch and bubble up errors to container Svelte components. Error boundaries similar to React seem like a good concept for that. It allows me to write code to handle the error - either replace the child component, or display the error. Please add this to Svelte. Solid error handling is necessary for a reliable application in production. |
This comment on the Error Boundary RFC indicates that some kind of error boundaries are (probably) coming in Svelte 5. |
closed? |
Closed by #14211 |
Are all of the above error classes caught by #14211? Including uncaught errors in |
Things that happen before Svelte's reactivity system can "see it" (like errors in event handlers or |
Adding try/catch to every single event handler is not realistically possible, see the real-world numbers in my comment above. The need is to handle all error classes, not just some error classes. Svelte could easily install a catch for all |
Handle them how? What is supposed to happen? We don't know what you would want to happen in response to it. And in case an event handler or onMount error happens outside the reactive tree then nothing lasting is damaged either way. |
I would like an Right now, they are sent by the browser to the global window as uncaught errors, which is a lot less helpful. There is no real way to handle them right now, other than manually adding 800 try/catch or wrapper functions everywhere. |
This is a feature suggestion for adding an error handling API to Svelte components based on this remark.
There is currently no built-in way to handle errors in Svelte components. React 16 introduced the concept of Error Boundaries to standardise this:
I imagine a similar concept would be a good addition to Svelte components. Maybe
declaratively, as event on element:
imperatively, as component life cycle event:
I would check if the error is handled inside the component - with the
onerror
handler - first, and only if it isn't handled there, have it bubble up and triggeron:error
. If a developer wants to handle the error inside the component and also wants to have it bubble up, they can usethis.fire('error', e)
withinonerror
.The text was updated successfully, but these errors were encountered: