create websocket for hot reloading

This commit is contained in:
Evan Almloff committed 2022-06-06 13:30:32 -05:00
1 parent 07199c8a64
commit e7cf382784
2 files changed
+69

No files matched your search

+3
View File
@@ -16,6 +16,7 @@ dioxus-html = { path = "../html", version = "^0.2.1", features = ["wasm-bind"] }
dioxus-interpreter-js = { path = "../interpreter", version = "^0.2.1", features = [
"web"
] }
dioxus-rsx-interpreter = { path = "../rsx_interpreter", version = "*", optional = true }
js-sys = "0.3.56"
wasm-bindgen = { version = "0.2.79", features = ["enable-interning"] }
@@ -30,6 +31,7 @@ futures-util = "0.3.19"
smallstr = "0.2.0"
serde-wasm-bindgen = "0.4.2"
futures-channel = "0.3.21"
serde_json = { version = "1.0", optional = true }
[dependencies.web-sys]
version = "0.3.56"
@@ -75,6 +77,7 @@ features = [
[features]
default = ["panic_hook"]
panic_hook = ["console_error_panic_hook"]
hot_reload = ["dioxus-rsx-interpreter", "web-sys/WebSocket", "web-sys/Location", "web-sys/MessageEvent", "serde_json"]
[dev-dependencies]
dioxus-core-macro = { path = "../core-macro" }
+66
View File
@@ -217,6 +217,72 @@ pub async fn run_with_props<T: 'static + Send>(root: Component<T>, root_props: T
let mut work_loop = ric_raf::RafLoop::new();
#[cfg(feature = "hot_reload")]
{
use dioxus_rsx_interpreter::error::Error;
use dioxus_rsx_interpreter::{ErrorHandler, SetRsxMessage, RSX_CONTEXT};
use futures_channel::mpsc::unbounded;
use futures_channel::mpsc::UnboundedSender;
use futures_util::StreamExt;
use wasm_bindgen::closure::Closure;
use wasm_bindgen::JsCast;
use web_sys::{MessageEvent, WebSocket};
let window = web_sys::window().unwrap();
let protocol = if window.location().protocol().unwrap() == "https:" {
"wss:"
} else {
"ws:"
};
let url = format!(
"{protocol} //{}/_dioxus/hot_reload",
window.location().host().unwrap()
);
let ws = WebSocket::new(&url).unwrap();
// change the rsx when new data is received
let cl = Closure::wrap(Box::new(|e: MessageEvent| {
if let Ok(text) = e.data().dyn_into::<js_sys::JsString>() {
let msg: SetRsxMessage = serde_json::from_str(&format!("{text}")).unwrap();
RSX_CONTEXT.insert(msg.location, msg.new_text);
}
}) as Box<dyn FnMut(MessageEvent)>);
ws.set_onmessage(Some(cl.as_ref().unchecked_ref()));
let (error_channel_sender, error_channel_receiver) = unbounded();
struct WebErrorHandler {
sender: UnboundedSender<Error>,
}
impl ErrorHandler for WebErrorHandler {
fn handle_error(&self, err: dioxus_rsx_interpreter::error::Error) {
self.sender.unbounded_send(err).unwrap();
}
}
RSX_CONTEXT.set_error_handler(WebErrorHandler {
sender: error_channel_sender,
});
// forward stream to the websocket
dom.base_scope().spawn_forever(async move {
error_channel_receiver
.for_each(|err| {
if let Error::RecompileRequiredError(err) = err {
ws.send_with_str(serde_json::to_string(&err).unwrap().as_str())
.unwrap();
}
futures_util::future::ready(())
})
.await;
});
}
loop {
log::trace!("waiting for work");
// if virtualdom has nothing, wait for it to have something before requesting idle time