Browse Source

unwind panics into error boundaries

Evan Almloff 1 year ago
parent
commit
2e7b8cb178
4 changed files with 69 additions and 23 deletions
  1. 36 21
      Cargo.lock
  2. 12 0
      examples/error_handle.rs
  3. 6 1
      packages/core/src/any_props.rs
  4. 15 1
      packages/core/src/error_boundary.rs

+ 36 - 21
Cargo.lock

@@ -2201,7 +2201,7 @@ version = "0.5.0-alpha.0"
 dependencies = [
  "criterion 0.3.6",
  "dioxus-config-macro",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-core-macro",
  "dioxus-desktop",
  "dioxus-fullstack",
@@ -2268,7 +2268,7 @@ dependencies = [
  "dioxus-autofmt",
  "dioxus-check",
  "dioxus-cli-config",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-hot-reload",
  "dioxus-html",
  "dioxus-rsx",
@@ -2357,6 +2357,20 @@ dependencies = [
  "tracing-subscriber",
 ]
 
+[[package]]
+name = "dioxus-core"
+version = "0.5.0-alpha.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f39bef0484998f724622964f04468ddfde7fd550f5f0f1aef9394306e9caba44"
+dependencies = [
+ "futures-channel",
+ "futures-util",
+ "longest-increasing-subsequence",
+ "rustc-hash",
+ "slab",
+ "tracing",
+]
+
 [[package]]
 name = "dioxus-core-macro"
 version = "0.5.0-alpha.0"
@@ -2387,7 +2401,7 @@ dependencies = [
  "core-foundation",
  "dioxus",
  "dioxus-cli-config",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-hooks",
  "dioxus-hot-reload",
  "dioxus-html",
@@ -2488,7 +2502,7 @@ name = "dioxus-hooks"
 version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-debug-cell",
  "dioxus-signals",
  "futures-channel",
@@ -2506,7 +2520,7 @@ name = "dioxus-hot-reload"
 version = "0.5.0-alpha.0"
 dependencies = [
  "chrono",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-html",
  "dioxus-rsx",
  "execute",
@@ -2523,7 +2537,7 @@ name = "dioxus-html"
 version = "0.5.0-alpha.0"
 dependencies = [
  "async-trait",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-html-internal-macro",
  "dioxus-rsx",
  "enumset",
@@ -2556,7 +2570,7 @@ dependencies = [
 name = "dioxus-interpreter-js"
 version = "0.5.0-alpha.0"
 dependencies = [
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-html",
  "js-sys",
  "md5",
@@ -2572,7 +2586,7 @@ name = "dioxus-lib"
 version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus-config-macro",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-core-macro",
  "dioxus-hooks",
  "dioxus-html",
@@ -2587,7 +2601,7 @@ dependencies = [
  "axum",
  "dioxus",
  "dioxus-cli-config",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-hot-reload",
  "dioxus-html",
  "dioxus-interpreter-js",
@@ -2621,7 +2635,7 @@ dependencies = [
  "anymap 1.0.0-beta.2",
  "dashmap",
  "dioxus",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-native-core",
  "dioxus-native-core-macro",
  "keyboard-types",
@@ -2730,7 +2744,7 @@ dependencies = [
 name = "dioxus-rsx"
 version = "0.5.0-alpha.0"
 dependencies = [
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "internment",
  "krates",
  "proc-macro2",
@@ -2745,7 +2759,7 @@ name = "dioxus-signals"
 version = "0.5.0-alpha.0"
 dependencies = [
  "dioxus",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "futures-channel",
  "futures-util",
  "generational-box",
@@ -2769,7 +2783,7 @@ dependencies = [
  "async-trait",
  "chrono",
  "dioxus",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-html",
  "dioxus-signals",
  "fern",
@@ -2800,7 +2814,7 @@ dependencies = [
  "criterion 0.3.6",
  "crossterm 0.26.1",
  "dioxus",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-hot-reload",
  "dioxus-html",
  "dioxus-native-core",
@@ -2818,7 +2832,7 @@ dependencies = [
  "async-trait",
  "console_error_panic_hook",
  "dioxus",
- "dioxus-core",
+ "dioxus-core 0.5.0-alpha.0",
  "dioxus-html",
  "dioxus-interpreter-js",
  "dioxus-ssr",
@@ -5701,10 +5715,11 @@ dependencies = [
 
 [[package]]
 name = "manganis"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c10916db4ed51967d92545eb5629ce1e1cc05c74da2cd2aab6ab6c57c2e838b6"
+checksum = "a42db80aa639f70d6bf1d2ef93612d2ffbb33f6ea17d473b91bfeb3f67bc24bc"
 dependencies = [
+ "dioxus-core 0.5.0-alpha.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "manganis-macro",
 ]
 
@@ -5737,9 +5752,9 @@ dependencies = [
 
 [[package]]
 name = "manganis-common"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82ee0f9002a9f5d7e3b662e55562996c60401bae16da23f3790c52e0823216ea"
+checksum = "176dfb4bb5592b0d130176add9893af527ab565fc1bcf58ece88acd6276688d1"
 dependencies = [
  "anyhow",
  "base64",
@@ -5753,9 +5768,9 @@ dependencies = [
 
 [[package]]
 name = "manganis-macro"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da50cc6074480dc6c255a09c9d48dd4a379e6162feb5d308ec33d5ba9da4e579"
+checksum = "ab2c2e11190c2f3d6133cffda5c955b463a7e90b7ba866e71e7dfa65fa97ddfc"
 dependencies = [
  "manganis-common",
  "proc-macro2",

+ 12 - 0
examples/error_handle.rs

@@ -20,6 +20,14 @@ fn app() -> Element {
             },
             DemoC { x: 1 }
         }
+
+        ErrorBoundary {
+            handle_error: |error: CapturedError| rsx! {
+                h1 { "Another error occurred" }
+                pre { "{error:#?}" }
+            },
+            ComponentPanic {}
+        }
     }
 }
 
@@ -40,3 +48,7 @@ fn DemoC(x: i32) -> Element {
         }
     }
 }
+
+fn ComponentPanic() -> Element {
+    panic!("This component panics")
+}

+ 6 - 1
packages/core/src/any_props.rs

@@ -1,4 +1,8 @@
-use crate::{nodes::RenderReturn, ComponentFunction};
+use crate::{
+    innerlude::{throw_error, CapturedPanic},
+    nodes::RenderReturn,
+    ComponentFunction,
+};
 use std::{any::Any, panic::AssertUnwindSafe};
 
 pub(crate) type BoxedAnyProps = Box<dyn AnyProps>;
@@ -79,6 +83,7 @@ impl<F: ComponentFunction<P, M> + Clone, P: Clone + 'static, M: 'static> AnyProp
             Err(err) => {
                 let component_name = self.name;
                 tracing::error!("Error while rendering component `{component_name}`: {err:?}");
+                throw_error::<()>(CapturedPanic { error: err });
                 RenderReturn::default()
             }
         }

+ 15 - 1
packages/core/src/error_boundary.rs

@@ -13,6 +13,20 @@ use std::{
     rc::Rc,
 };
 
+/// A panic in a component that was caught by an error boundary.
+///
+/// NOTE: WASM currently does not support caching unwinds, so this struct will not be created in WASM.
+pub struct CapturedPanic {
+    /// The error that was caught
+    pub error: Box<dyn Any + 'static>,
+}
+
+impl Debug for CapturedPanic {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("CapturedPanic").finish()
+    }
+}
+
 /// Provide an error boundary to catch errors from child components
 pub fn use_error_boundary() -> ErrorBoundary {
     use_hook(|| provide_context(ErrorBoundary::new()))
@@ -201,7 +215,7 @@ pub trait Throw<S = ()>: Sized {
     }
 }
 
-fn throw_error<T>(e: impl Debug + 'static) -> Option<T> {
+pub(crate) fn throw_error<T>(e: impl Debug + 'static) -> Option<T> {
     if let Some(cx) = try_consume_context::<ErrorBoundary>() {
         match current_scope_id() {
             Some(id) => cx.insert_error(id, Box::new(e), Backtrace::capture()),