-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Dash Dev Tools #292
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
Comments
React 16 introduced Error Boundaries Error boundaries are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them. If we upgrade to react 16 we can
Or even render the app with a small error message bar like here or even design something nice like the atom plugin error message above. I'll see if I can get a proof of concept / see if it really is that easy... |
+1 for error-boundaries! it makes React development a lot easier and makes working with sometimes-buggy apps a lot nicer: just parts of the app become unusable instead of all of them :) |
Error-boundaries sound great. Would be very interesting to see that in a proof of concept! I'm not sure about the control bar idea - but's that's just my general preference. Don't really like development UI to be on my web application! But what about maybe a browser plugin, like React devTools has? |
Ditto, I like the error boundary idea. |
Error boundaries work pretty well. I wrapped the What may pose a difficulty is that React refuses to render any component which is throwing an exception, meaning components would need to be perfect and not throw any errors. Previously, Dash components could be buggy (e.g. throw some errors to console) and stay rendered on the app (e.g. in this example, you can keep clicking the button and it would stay while throwing an error each click). With this kind of update we would either need to completely unmount the app and display an error message, or put error handlers lower down in the component tree. I think the logic behind not rendering any components which are throwing an error in a lifecycle method is solid, explained here |
Looking into this further, it looks like Error Boundaries are not perfect since they only catch errors in lifecycle methods, constructors, and render methods. Front-end errors will work fine, but server side 500 errors will not be caught since they originate from event handlers. There are two workarounds I have found to get both error types in the same place, which are a little hacky but might be worth it.
perhaps we could catch errors here with something like
which would push them up into the react error boundary. |
The @rmarren1 |
True @T4rk1n, I forgot about those other endpoints. I think then that catching errors in the following three
In fact the string |
@rmarren1 The first two are wrappers, find the usage of those. Could dispatch the error from there, the response content type should be |
(semi-related to the immediate discussion above. Here's another interesting solution for displaying logs in the browser, it could be a separate endpoint and read from a file: https://github.com/mozilla-frontend-infra/react-lazylog) |
^^ I like that, looks like CircleCI output I've been looking into handling things on the Flask side now. We need a way to catch errors in debug mode and do something with them that makes it available to the front end. The LazyLog component looks great for this (haven't tried this part, but it looks like with the 'stream' attribute set to true we can continuously listen to an error file), then we would only need to serve an error file from Flask and then write to that file when an exception occurs. This is what is usually done, but this custom handler is only fired when
The flask Specifically the got_request_exception signal. This signal is sent when an exception happens during request processing. It is sent before the standard exception handling kicks in and even in debug mode, where no exception handling happens. The exception itself is passed to the subscriber as exception. I tested this module in Dash and it works nicely 😄
to I think this is way easier than catching all the exceptions in the front end! I'll see if I can get it working end-to-end, E.g., server-side errors read by LazyLog which triggers some high order component in react to render an error message. Then we just need to feed front-end exceptions caught with the React Error Boundaries into the same rendering mechanism and I think it would work |
I have a work in progress going in these two pull requests Still trying to figure some small quirks out, but it is at a point where it does what it should locally. |
This is very very cool @rmarren1 ! A few comments:
Finally, re browser extension vs rendering the dev tools within the app: I'm a pretty strong proponent of shipping this dev tools UI as part of the app for a few reasons:
Of course, if it's part of the app, it needs to be really ergonomic. So, let's keep experimenting with different UIs. I'll loop back on this issue about getting some design talent to help us out as well. |
One point on the UI is that if we are dealing with a front-end error (originating from a React lifecycle method of come component in the app) then the app will unmount by default as of React 16, so in the current solution we couldn't render the app and the error message. We could include an error boundary around every component in the tree, then figure out a way to bubble caught errors up to a higher-order error handler which will display the message along with the app (excluding the component in the app which caused the error). We might even be able to put a red-box around the space where the buggy component used to be, which would make it super apparent where the error comes from. I'll see if I can do this in the WIP I have. |
Wow, that would be really sweet |
Werkzueg works. Actually this may be a better solution than pushing errors from Flask over a socket, and you can overlay it onto a running app. I'll see what more I can do with the front-end errors. commits for this in https://github.com/rmarren1/dash-renderer/tree/dash-dev-tools |
Wow! does the werkzeug console work too? |
I don't think so, it says "If you enable JavaScript you can also use additional features such as code execution (if the evalex feature is enabled), automatic pasting of the exceptions and much more.", probably because I am using dangerouslySetInnerHtml |
Yeah, sounds right. It looks like browser's don't support script tags that are inserted through |
Maybe embed the html in an |
Played around with a bunch of stuff.
surprisingly works perfectly, Werkzueg console and all. The only bad part is it takes over the entire screen so we can't embed it over the app, but we might be able to fix that in the future. |
I don't mind it taking the whole screen, an error still has to be fixed and it is in your face so you can't ignore it. |
@chriddyp how did you generate the DAG graphic in screenshot shown above? Seems super useful |
@mkhorton it came from https://github.com/nicolaskruchten/dash_callback_chain although that repo contains just a proof-of-concept and hasn't been tested with newer versions of Dash :) |
Made another pre-release at |
Related redux devtools for inspiration: https://github.com/reduxjs/redux-devtools |
Here’s a mock up of what “dash dev tools” could look like. Slides 2-6 are just the werkzeug debugger themed with CSS. Slides 7-16 are the front-end error messages and the general container for other dev-tools things that we might add (like the DAG graph, hot reloading options one day maybe, etc). would love any and all feedback. |
Woah, the callback graph would make it a lot easier to reason about complex Dash apps! |
Mostly finished in plotly/dash-renderer#100. The only exception is the Python debugger. Still a good idea, but we should discuss in a separate issue if we get the chance to go forward with it. |
In https://github.com/orgs/plotly/projects/3, many of our issues involve Dash's front-end: Front-end error handling, front-end live-DAG, front-end hot-reload.
I'd like to open this issue to discuss an architecture for handling these requirements.
Some framing:
JavaScript Error Handling
For example, consider Atom's plugins:

Python Error Handling
Could we use the same architecture that we use for JavaScript errors to display python errors? That way, the user never needs to look at the terminal for errors, they only need to focus on their app.
For example, consider create-react-app:

or werkzeug:

Hot Reloading
If we had hot-reloading, could we build a nice little "control bar" that users could use to configure hot reloading? For example, it could:
Displaying the DAG

If we wanted to display the DAG to the user, could we place this in the Dash Dev Tools container as well?
cc @plotly/dash
The text was updated successfully, but these errors were encountered: