From 064bee4a9ff3d481622e56ed1e6da5a391020fa7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 1 May 2023 17:34:30 -0500 Subject: [PATCH] spawn hot reloading in a seperate thread --- .../examples/axum-hello-world/Cargo.toml | 8 +----- .../examples/axum-hello-world/src/main.rs | 15 ++++++++++- .../server/examples/axum-router/Cargo.toml | 8 +----- .../server/examples/axum-router/src/main.rs | 13 +++++++++ .../examples/salvo-hello-world/Cargo.toml | 8 +----- .../examples/salvo-hello-world/src/main.rs | 13 +++++++++ .../examples/warp-hello-world/Cargo.toml | 8 +----- .../examples/warp-hello-world/src/main.rs | 15 ++++++++++- packages/server/src/adapters/axum_adapter.rs | 18 +++++-------- packages/server/src/adapters/salvo_adapter.rs | 15 +++++------ packages/server/src/adapters/warp_adapter.rs | 27 ++++++++++--------- packages/server/src/hot_reload.rs | 15 +++++++++++ packages/server/src/render.rs | 8 +++--- 13 files changed, 106 insertions(+), 65 deletions(-) diff --git a/packages/server/examples/axum-hello-world/Cargo.toml b/packages/server/examples/axum-hello-world/Cargo.toml index b2c14561d..27c6af08b 100644 --- a/packages/server/examples/axum-hello-world/Cargo.toml +++ b/packages/server/examples/axum-hello-world/Cargo.toml @@ -13,15 +13,9 @@ dioxus-server = { path = "../../" } axum = { version = "0.6.12", optional = true } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" +execute = "0.2.12" [features] default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum"] web = ["dioxus-web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/axum-hello-world/src/main.rs b/packages/server/examples/axum-hello-world/src/main.rs index 6b6f32db7..3db117c02 100644 --- a/packages/server/examples/axum-hello-world/src/main.rs +++ b/packages/server/examples/axum-hello-world/src/main.rs @@ -19,6 +19,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + PostServerData::register().unwrap(); GetServerData::register().unwrap(); tokio::runtime::Runtime::new() @@ -65,7 +78,7 @@ fn app(cx: Scope) -> Element { } } }, - "Run a server function" + "Run a server function! testing1234" } "Server said: {text}" }) diff --git a/packages/server/examples/axum-router/Cargo.toml b/packages/server/examples/axum-router/Cargo.toml index 3e137d8f6..2ba621c9c 100644 --- a/packages/server/examples/axum-router/Cargo.toml +++ b/packages/server/examples/axum-router/Cargo.toml @@ -16,15 +16,9 @@ tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" tower-http = { version = "0.4.0", features = ["fs"], optional = true } http = { version = "0.2.9", optional = true } +execute = "0.2.12" [features] default = ["web"] ssr = ["axum", "tokio", "dioxus-server/axum", "tower-http", "http"] web = ["dioxus-web", "dioxus-router/web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/axum-router/src/main.rs b/packages/server/examples/axum-router/src/main.rs index 3994eeb51..0b5e55e4f 100644 --- a/packages/server/examples/axum-router/src/main.rs +++ b/packages/server/examples/axum-router/src/main.rs @@ -20,6 +20,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + use axum::extract::State; PostServerData::register().unwrap(); GetServerData::register().unwrap(); diff --git a/packages/server/examples/salvo-hello-world/Cargo.toml b/packages/server/examples/salvo-hello-world/Cargo.toml index 9146ce3e2..50c92f237 100644 --- a/packages/server/examples/salvo-hello-world/Cargo.toml +++ b/packages/server/examples/salvo-hello-world/Cargo.toml @@ -13,15 +13,9 @@ dioxus-server = { path = "../../" } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" salvo = { version = "0.37.9", optional = true } +execute = "0.2.12" [features] default = ["web"] ssr = ["salvo", "tokio", "dioxus-server/salvo"] web = ["dioxus-web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/salvo-hello-world/src/main.rs b/packages/server/examples/salvo-hello-world/src/main.rs index ff1081077..25ebbbff9 100644 --- a/packages/server/examples/salvo-hello-world/src/main.rs +++ b/packages/server/examples/salvo-hello-world/src/main.rs @@ -19,6 +19,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + use salvo::prelude::*; PostServerData::register().unwrap(); GetServerData::register().unwrap(); diff --git a/packages/server/examples/warp-hello-world/Cargo.toml b/packages/server/examples/warp-hello-world/Cargo.toml index e182494b0..2c5d175ae 100644 --- a/packages/server/examples/warp-hello-world/Cargo.toml +++ b/packages/server/examples/warp-hello-world/Cargo.toml @@ -13,15 +13,9 @@ dioxus-server = { path = "../../" } tokio = { version = "1.27.0", features = ["full"], optional = true } serde = "1.0.159" warp = { version = "0.3.3", optional = true } +execute = "0.2.12" [features] default = ["web"] ssr = ["warp", "tokio", "dioxus-server/warp"] web = ["dioxus-web"] - -[profile.release] -lto = true -panic = "abort" -opt-level = 3 -strip = true -codegen-units = 1 diff --git a/packages/server/examples/warp-hello-world/src/main.rs b/packages/server/examples/warp-hello-world/src/main.rs index 04684f803..3bbb95227 100644 --- a/packages/server/examples/warp-hello-world/src/main.rs +++ b/packages/server/examples/warp-hello-world/src/main.rs @@ -19,6 +19,19 @@ fn main() { ); #[cfg(feature = "ssr")] { + // Start hot reloading + hot_reload_init!(dioxus_hot_reload::Config::new().with_rebuild_callback(|| { + execute::shell("dioxus build --features web") + .spawn() + .unwrap() + .wait() + .unwrap(); + execute::shell("cargo run --features ssr --no-default-features") + .spawn() + .unwrap(); + true + })); + PostServerData::register().unwrap(); GetServerData::register().unwrap(); tokio::runtime::Runtime::new() @@ -45,7 +58,7 @@ fn app(cx: Scope) -> Element { cx.render(rsx! { h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } + button { onclick: move |_| count += 10, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| { diff --git a/packages/server/src/adapters/axum_adapter.rs b/packages/server/src/adapters/axum_adapter.rs index f4b05e199..6ca82b1e5 100644 --- a/packages/server/src/adapters/axum_adapter.rs +++ b/packages/server/src/adapters/axum_adapter.rs @@ -290,11 +290,7 @@ where self.nest( "/_dioxus", Router::new() - .route( - "/hot_reload", - get(hot_reload_handler) - .with_state(crate::hot_reload::HotReloadState::default()), - ) + .route("/hot_reload", get(hot_reload_handler)) .route( "/disconnect", get(|ws: WebSocketUpgrade| async { @@ -420,14 +416,13 @@ fn report_err(e: E) -> Response { /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] -pub async fn hot_reload_handler( - ws: WebSocketUpgrade, - State(state): State, -) -> impl IntoResponse { +pub async fn hot_reload_handler(ws: WebSocketUpgrade) -> impl IntoResponse { use axum::extract::ws::Message; use futures_util::StreamExt; - ws.on_upgrade(|mut socket| async move { + let state = crate::hot_reload::spawn_hot_reload().await; + + ws.on_upgrade(move |mut socket| async move { println!("🔥 Hot Reload WebSocket connected"); { // update any rsx calls that changed before the websocket connected. @@ -448,7 +443,8 @@ pub async fn hot_reload_handler( println!("finished"); } - let mut rx = tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver); + let mut rx = + tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver.clone()); while let Some(change) = rx.next().await { if let Some(template) = change { let template = { serde_json::to_string(&template).unwrap() }; diff --git a/packages/server/src/adapters/salvo_adapter.rs b/packages/server/src/adapters/salvo_adapter.rs index 3751211e4..75387d1f9 100644 --- a/packages/server/src/adapters/salvo_adapter.rs +++ b/packages/server/src/adapters/salvo_adapter.rs @@ -455,9 +455,7 @@ impl HotReloadHandler { /// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] #[derive(Default)] -pub struct HotReloadHandler { - state: crate::hot_reload::HotReloadState, -} +pub struct HotReloadHandler; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "ssr"))] #[handler] @@ -471,10 +469,10 @@ impl HotReloadHandler { use salvo::ws::Message; use salvo::ws::WebSocketUpgrade; - let state = self.state.clone(); + let state = crate::hot_reload::spawn_hot_reload().await; WebSocketUpgrade::new() - .upgrade(req, res, |mut websocket| async move { + .upgrade(req, res, move |mut websocket| async move { use futures_util::StreamExt; println!("🔥 Hot Reload WebSocket connected"); @@ -497,8 +495,9 @@ impl HotReloadHandler { println!("finished"); } - let mut rx = - tokio_stream::wrappers::WatchStream::from_changes(state.message_receiver); + let mut rx = tokio_stream::wrappers::WatchStream::from_changes( + state.message_receiver.clone(), + ); while let Some(change) = rx.next().await { if let Some(template) = change { let template = { serde_json::to_string(&template).unwrap() }; @@ -518,7 +517,7 @@ async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::h use salvo::ws::WebSocketUpgrade; WebSocketUpgrade::new() .upgrade(req, res, |mut ws| async move { - let _ = dbg!(ws.send(salvo::ws::Message::text("connected")).await); + let _ = ws.send(salvo::ws::Message::text("connected")).await; while let Some(msg) = ws.recv().await { if msg.is_err() { return; diff --git a/packages/server/src/adapters/warp_adapter.rs b/packages/server/src/adapters/warp_adapter.rs index 3d41d76cf..9a4ec7af4 100644 --- a/packages/server/src/adapters/warp_adapter.rs +++ b/packages/server/src/adapters/warp_adapter.rs @@ -372,12 +372,10 @@ pub fn connect_hot_reload() -> impl Filter impl Filter impl Filter); @@ -432,10 +433,12 @@ pub fn connect_hot_reload() -> impl Filter = tokio::sync::OnceCell::const_new(); +pub(crate) async fn spawn_hot_reload() -> &'static HotReloadState { + HOT_RELOAD_STATE + .get_or_init(|| async { + println!("spinning up hot reloading"); + let r = tokio::task::spawn_blocking(HotReloadState::default) + .await + .unwrap(); + println!("hot reloading ready"); + r + }) + .await +} diff --git a/packages/server/src/render.rs b/packages/server/src/render.rs index 1d32e2acd..a05a63801 100644 --- a/packages/server/src/render.rs +++ b/packages/server/src/render.rs @@ -55,6 +55,7 @@ impl SSRState { #[cfg(all(debug_assertions, feature = "hot-reload"))] { + // In debug mode, we need to add a script to the page that will reload the page if the websocket disconnects to make full recompile hot reloads work let disconnect_js = r#"(function () { const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; const url = protocol + '//' + window.location.host + '/_dioxus/disconnect'; @@ -77,10 +78,9 @@ impl SSRState { // on initial page load connect to the disconnect ws const ws = new WebSocket(url); - ws.onopen = () => { - // if we disconnect, start polling - ws.onclose = reload_upon_connect; - }; + // if we disconnect, start polling + ws.onmessage = (m) => {console.log(m)}; + ws.onclose = reload_upon_connect; })()"#; html += r#"