show panics in the toast in wasm (#4582)
This commit is contained in:
1 parent
165447a647
commit
74163984be
7 files changed
+68
-12
No files matched your search
Generated
-1
@@ -5686,7 +5686,6 @@ dependencies = [
|
|||||||
name = "dioxus-logger"
|
name = "dioxus-logger"
|
||||||
version = "0.7.0-rc.0"
|
version = "0.7.0-rc.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
|
||||||
"dioxus",
|
"dioxus",
|
||||||
"dioxus-cli-config",
|
"dioxus-cli-config",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|||||||
@@ -307,7 +307,6 @@ criterion = { version = "0.6" }
|
|||||||
cargo_metadata = "0.19.2"
|
cargo_metadata = "0.19.2"
|
||||||
parking_lot = "0.12.4"
|
parking_lot = "0.12.4"
|
||||||
tracing-wasm = "0.2.1"
|
tracing-wasm = "0.2.1"
|
||||||
console_error_panic_hook = "0.1.7"
|
|
||||||
base16 = "0.2.1"
|
base16 = "0.2.1"
|
||||||
digest = "0.10.7"
|
digest = "0.10.7"
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ default = []
|
|||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
tracing-wasm = { workspace = true }
|
tracing-wasm = { workspace = true }
|
||||||
console_error_panic_hook = { workspace = true }
|
|
||||||
|
|
||||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||||
tracing-subscriber = { workspace = true, features = ["fmt"] }
|
tracing-subscriber = { workspace = true, features = ["fmt"] }
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ pub fn init(level: Level) -> Result<(), SetGlobalDefaultError> {
|
|||||||
let layer = tracing_wasm::WASMLayer::new(layer_config);
|
let layer = tracing_wasm::WASMLayer::new(layer_config);
|
||||||
let reg = Registry::default().with(layer);
|
let reg = Registry::default().with(layer);
|
||||||
|
|
||||||
console_error_panic_hook::set_once();
|
|
||||||
set_global_default(reg)
|
set_global_default(reg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use wasm_bindgen::JsCast as _;
|
|||||||
/// ```
|
/// ```
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub(crate) hydrate: bool,
|
pub(crate) hydrate: bool,
|
||||||
|
pub(crate) panic_hook: bool,
|
||||||
pub(crate) root: ConfigRoot,
|
pub(crate) root: ConfigRoot,
|
||||||
#[cfg(feature = "document")]
|
#[cfg(feature = "document")]
|
||||||
pub(crate) history: Option<Rc<dyn dioxus_history::History>>,
|
pub(crate) history: Option<Rc<dyn dioxus_history::History>>,
|
||||||
@@ -96,6 +97,7 @@ impl Default for Config {
|
|||||||
root: ConfigRoot::RootName("main".to_string()),
|
root: ConfigRoot::RootName("main".to_string()),
|
||||||
#[cfg(feature = "document")]
|
#[cfg(feature = "document")]
|
||||||
history: None,
|
history: None,
|
||||||
|
panic_hook: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,12 @@
|
|||||||
//! This sets up a websocket connection to the devserver and handles messages from it.
|
//! This sets up a websocket connection to the devserver and handles messages from it.
|
||||||
//! We also set up a little recursive timer that will attempt to reconnect if the connection is lost.
|
//! We also set up a little recursive timer that will attempt to reconnect if the connection is lost.
|
||||||
|
|
||||||
use std::fmt::Display;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use dioxus_devtools::{DevserverMsg, HotReloadMsg};
|
use dioxus_devtools::{DevserverMsg, HotReloadMsg};
|
||||||
use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
|
use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
|
||||||
use js_sys::JsString;
|
use js_sys::JsString;
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::time::Duration;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen::{closure::Closure, JsValue};
|
use wasm_bindgen::{closure::Closure, JsValue};
|
||||||
use web_sys::{window, CloseEvent, MessageEvent, WebSocket};
|
use web_sys::{window, CloseEvent, MessageEvent, WebSocket};
|
||||||
@@ -21,15 +21,23 @@ const POLL_INTERVAL_SCALE_FACTOR: i32 = 2;
|
|||||||
const TOAST_TIMEOUT: Duration = Duration::from_secs(5);
|
const TOAST_TIMEOUT: Duration = Duration::from_secs(5);
|
||||||
const TOAST_TIMEOUT_LONG: Duration = Duration::from_secs(3600); // Duration::MAX is too long for JS.
|
const TOAST_TIMEOUT_LONG: Duration = Duration::from_secs(3600); // Duration::MAX is too long for JS.
|
||||||
|
|
||||||
pub(crate) fn init() -> UnboundedReceiver<HotReloadMsg> {
|
pub(crate) fn init(config: &crate::Config) -> UnboundedReceiver<HotReloadMsg> {
|
||||||
// Create the tx/rx pair that we'll use for the top-level future in the dioxus loop
|
// Create the tx/rx pair that we'll use for the top-level future in the dioxus loop
|
||||||
let (tx, rx) = unbounded();
|
let (tx, rx) = unbounded();
|
||||||
|
|
||||||
// Wire up the websocket to the devserver
|
// Wire up the websocket to the devserver
|
||||||
make_ws(tx.clone(), POLL_INTERVAL_MIN, false);
|
make_ws(tx.clone(), POLL_INTERVAL_MIN, false);
|
||||||
|
|
||||||
|
// Set up the playground
|
||||||
playground(tx);
|
playground(tx);
|
||||||
|
|
||||||
|
// Set up the panic hook
|
||||||
|
if config.panic_hook {
|
||||||
|
std::panic::set_hook(Box::new(|info| {
|
||||||
|
hook_impl(info);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +231,7 @@ pub(crate) fn show_toast(
|
|||||||
_ = js_sys::eval(&format!(
|
_ = js_sys::eval(&format!(
|
||||||
r#"
|
r#"
|
||||||
if (typeof {js_fn_name} !== "undefined") {{
|
if (typeof {js_fn_name} !== "undefined") {{
|
||||||
window.{js_fn_name}("{header_text}", "{message}", "{level}", {as_ms});
|
window.{js_fn_name}(`{header_text}`, `{message}`, `{level}`, {as_ms});
|
||||||
}}
|
}}
|
||||||
"#,
|
"#,
|
||||||
));
|
));
|
||||||
@@ -289,3 +297,53 @@ fn playground(tx: UnboundedSender<HotReloadMsg>) {
|
|||||||
|
|
||||||
binding.forget();
|
binding.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hook_impl(info: &std::panic::PanicHookInfo) {
|
||||||
|
#[wasm_bindgen]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(js_namespace = console)]
|
||||||
|
fn error(msg: String);
|
||||||
|
|
||||||
|
type Error;
|
||||||
|
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
fn new() -> Error;
|
||||||
|
|
||||||
|
#[wasm_bindgen(structural, method, getter)]
|
||||||
|
fn stack(error: &Error) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut msg = info.to_string();
|
||||||
|
|
||||||
|
// Add the error stack to our message.
|
||||||
|
//
|
||||||
|
// This ensures that even if the `console` implementation doesn't
|
||||||
|
// include stacks for `console.error`, the stack is still available
|
||||||
|
// for the user. Additionally, Firefox's console tries to clean up
|
||||||
|
// stack traces, and ruins Rust symbols in the process
|
||||||
|
// (https://bugzilla.mozilla.org/show_bug.cgi?id=1519569) but since
|
||||||
|
// it only touches the logged message's associated stack, and not
|
||||||
|
// the message's contents, by including the stack in the message
|
||||||
|
// contents we make sure it is available to the user.
|
||||||
|
msg.push_str("\n\nStack:\n\n");
|
||||||
|
let e = Error::new();
|
||||||
|
let stack = e.stack();
|
||||||
|
msg.push_str(&stack);
|
||||||
|
|
||||||
|
// Safari's devtools, on the other hand, _do_ mess with logged
|
||||||
|
// messages' contents, so we attempt to break their heuristics for
|
||||||
|
// doing that by appending some whitespace.
|
||||||
|
// https://github.com/rustwasm/console_error_panic_hook/issues/7
|
||||||
|
msg.push_str("\n\n");
|
||||||
|
|
||||||
|
// Log the panic with `console.error`!
|
||||||
|
error(msg.clone());
|
||||||
|
|
||||||
|
show_toast(
|
||||||
|
"App panicked! See console for details.",
|
||||||
|
&msg,
|
||||||
|
ToastLevel::Error,
|
||||||
|
TOAST_TIMEOUT_LONG,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -51,6 +51,9 @@ pub use hydration::*;
|
|||||||
/// wasm_bindgen_futures::spawn_local(app_fut);
|
/// wasm_bindgen_futures::spawn_local(app_fut);
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn run(mut virtual_dom: VirtualDom, web_config: Config) -> ! {
|
pub async fn run(mut virtual_dom: VirtualDom, web_config: Config) -> ! {
|
||||||
|
#[cfg(all(feature = "devtools", debug_assertions))]
|
||||||
|
let mut hotreload_rx = devtools::init(&web_config);
|
||||||
|
|
||||||
#[cfg(feature = "document")]
|
#[cfg(feature = "document")]
|
||||||
if let Some(history) = web_config.history.clone() {
|
if let Some(history) = web_config.history.clone() {
|
||||||
virtual_dom.in_runtime(|| dioxus_core::ScopeId::ROOT.provide_context(history));
|
virtual_dom.in_runtime(|| dioxus_core::ScopeId::ROOT.provide_context(history));
|
||||||
@@ -61,9 +64,6 @@ pub async fn run(mut virtual_dom: VirtualDom, web_config: Config) -> ! {
|
|||||||
|
|
||||||
let runtime = virtual_dom.runtime();
|
let runtime = virtual_dom.runtime();
|
||||||
|
|
||||||
#[cfg(all(feature = "devtools", debug_assertions))]
|
|
||||||
let mut hotreload_rx = devtools::init();
|
|
||||||
|
|
||||||
// If the hydrate feature is enabled, launch the client with hydration enabled
|
// If the hydrate feature is enabled, launch the client with hydration enabled
|
||||||
let should_hydrate = web_config.hydrate || cfg!(feature = "hydrate");
|
let should_hydrate = web_config.hydrate || cfg!(feature = "hydrate");
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user