Explorar el Código

Always run toast eval inside the runtime (#3313)

Evan Almloff hace 6 meses
padre
commit
d89ab3cfad
Se han modificado 2 ficheros con 23 adiciones y 7 borrados
  1. 20 4
      packages/web/src/devtools.rs
  2. 3 3
      packages/web/src/lib.rs

+ 20 - 4
packages/web/src/devtools.rs

@@ -4,9 +4,11 @@
 //! We also set up a little recursive timer that will attempt to reconnect if the connection is lost.
 
 use std::fmt::Display;
+use std::rc::Rc;
 use std::time::Duration;
 
-use dioxus_core::ScopeId;
+use dioxus_core::prelude::RuntimeGuard;
+use dioxus_core::{Runtime, ScopeId};
 use dioxus_devtools::{DevserverMsg, HotReloadMsg};
 use dioxus_document::eval;
 use futures_channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender};
@@ -22,17 +24,22 @@ const POLL_INTERVAL_SCALE_FACTOR: i32 = 2;
 /// Amount of time that toats should be displayed.
 const TOAST_TIMEOUT: Duration = Duration::from_secs(5);
 
-pub(crate) fn init() -> UnboundedReceiver<HotReloadMsg> {
+pub(crate) fn init(runtime: Rc<Runtime>) -> UnboundedReceiver<HotReloadMsg> {
     // Create the tx/rx pair that we'll use for the top-level future in the dioxus loop
     let (tx, rx) = unbounded();
 
     // Wire up the websocket to the devserver
-    make_ws(tx, POLL_INTERVAL_MIN, false);
+    make_ws(runtime, tx, POLL_INTERVAL_MIN, false);
 
     rx
 }
 
-fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool) {
+fn make_ws(
+    runtime: Rc<Runtime>,
+    tx: UnboundedSender<HotReloadMsg>,
+    poll_interval: i32,
+    reload: bool,
+) {
     // Get the location of the devserver, using the current location plus the /_dioxus path
     // The idea here being that the devserver is always located on the /_dioxus behind a proxy
     let location = web_sys::window().unwrap().location();
@@ -49,6 +56,7 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
 
     // Set the onmessage handler to bounce messages off to the main dioxus loop
     let tx_ = tx.clone();
+    let runtime_ = runtime.clone();
     ws.set_onmessage(Some(
         Closure::<dyn FnMut(MessageEvent)>::new(move |e: MessageEvent| {
             let Ok(text) = e.data().dyn_into::<JsString>() else {
@@ -72,6 +80,7 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
 
                 // The devserver is telling us that it started a full rebuild. This does not mean that it is ready.
                 Ok(DevserverMsg::FullReloadStart) => show_toast(
+                    runtime_.clone(),
                     "Your app is being rebuilt.",
                     "A non-hot-reloadable change occurred and we must rebuild.",
                     ToastLevel::Info,
@@ -80,6 +89,7 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
                 ),
                 // The devserver is telling us that the full rebuild failed.
                 Ok(DevserverMsg::FullReloadFailed) => show_toast(
+                    runtime_.clone(),
                     "Oops! The build failed.",
                     "We tried to rebuild your app, but something went wrong.",
                     ToastLevel::Error,
@@ -90,6 +100,7 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
                 // The devserver is telling us to reload the whole page
                 Ok(DevserverMsg::FullReloadCommand) => {
                     show_toast(
+                        runtime_.clone(),
                         "Successfully rebuilt.",
                         "Your app was rebuilt successfully and without error.",
                         ToastLevel::Success,
@@ -121,11 +132,13 @@ fn make_ws(tx: UnboundedSender<HotReloadMsg>, poll_interval: i32, reload: bool)
 
             // set timeout to reload the page in timeout_ms
             let tx = tx.clone();
+            let runtime = runtime.clone();
             web_sys::window()
                 .unwrap()
                 .set_timeout_with_callback_and_timeout_and_arguments_0(
                     Closure::<dyn FnMut()>::new(move || {
                         make_ws(
+                            runtime.clone(),
                             tx.clone(),
                             POLL_INTERVAL_MAX.min(poll_interval * POLL_INTERVAL_SCALE_FACTOR),
                             true,
@@ -189,6 +202,7 @@ impl Display for ToastLevel {
 
 /// Displays a toast to the developer.
 fn show_toast(
+    runtime: Rc<Runtime>,
     header_text: &str,
     message: &str,
     level: ToastLevel,
@@ -202,6 +216,8 @@ fn show_toast(
         false => "showDXToast",
     };
 
+    // Create the guard before running eval which uses the global runtime context
+    let _guard = RuntimeGuard::new(runtime);
     ScopeId::ROOT.in_runtime(|| {
         eval(&format!(
             r#"

+ 3 - 3
packages/web/src/lib.rs

@@ -66,11 +66,11 @@ pub async fn run(mut virtual_dom: VirtualDom, web_config: Config) -> ! {
     #[cfg(feature = "document")]
     virtual_dom.in_runtime(document::init_document);
 
-    #[cfg(all(feature = "devtools", debug_assertions))]
-    let mut hotreload_rx = devtools::init();
-
     let runtime = virtual_dom.runtime();
 
+    #[cfg(all(feature = "devtools", debug_assertions))]
+    let mut hotreload_rx = devtools::init(runtime.clone());
+
     let should_hydrate = web_config.hydrate;
 
     let mut websys_dom = WebsysDom::new(web_config, runtime);