فهرست منبع

implement hot reloading for liveview

Evan Almloff 2 سال پیش
والد
کامیت
e5e1abbdac
4فایلهای تغییر یافته به همراه58 افزوده شده و 4 حذف شده
  1. 7 4
      packages/liveview/Cargo.toml
  2. 31 0
      packages/liveview/src/hot_reload.rs
  3. 2 0
      packages/liveview/src/lib.rs
  4. 18 0
      packages/liveview/src/pool.rs

+ 7 - 4
packages/liveview/Cargo.toml

@@ -13,6 +13,10 @@ license = "MIT/Apache-2.0"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+dioxus-html = { path = "../html", features = ["serialize"], version = "^0.3.0" }
+dioxus-core = { path = "../core", features = ["serialize"], version = "^0.3.0" }
+dioxus-interpreter-js = { path = "../interpreter", version = "0.3.0" }
+
 tokio = { version = "1.23.0", features = ["full"] }
 futures-util = { version = "0.3.25", default-features = false, features = [
     "sink",
@@ -25,9 +29,7 @@ serde = { version = "1.0.151", features = ["derive"] }
 serde_json = "1.0.91"
 tokio-util = { version = "0.7.4", features = ["full"] }
 
-dioxus-html = { path = "../html", features = ["serialize"], version = "^0.3.0" }
-dioxus-core = { path = "../core", features = ["serialize"], version = "^0.3.0" }
-dioxus-interpreter-js = { path = "../interpreter", version = "0.3.0" }
+interprocess = { version = "1.2.1", optional = true }
 
 # warp
 warp = { version = "0.3.3", optional = true }
@@ -56,8 +58,9 @@ salvo = { version = "0.37.7", features = ["affix", "ws"] }
 tower = "0.4.13"
 
 [features]
-default = []
+default = ["hot-reload"]
 # actix = ["actix-files", "actix-web", "actix-ws"]
+hot-reload = ["interprocess"]
 
 [[example]]
 name = "axum"

+ 31 - 0
packages/liveview/src/hot_reload.rs

@@ -0,0 +1,31 @@
+#![allow(dead_code)]
+
+use dioxus_core::Template;
+
+use interprocess::local_socket::LocalSocketStream;
+use std::io::{BufRead, BufReader};
+use tokio::sync::mpsc::UnboundedSender;
+
+pub(crate) fn init(proxy: UnboundedSender<Template<'static>>) {
+    std::thread::spawn(move || {
+        let temp_file = std::env::temp_dir().join("@dioxusin");
+        if let Ok(socket) = LocalSocketStream::connect(temp_file.as_path()) {
+            let mut buf_reader = BufReader::new(socket);
+            loop {
+                let mut buf = String::new();
+                match buf_reader.read_line(&mut buf) {
+                    Ok(_) => {
+                        let template: Template<'static> =
+                            serde_json::from_str(Box::leak(buf.into_boxed_str())).unwrap();
+                        proxy.send(template).unwrap();
+                    }
+                    Err(err) => {
+                        if err.kind() != std::io::ErrorKind::WouldBlock {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+    });
+}

+ 2 - 0
packages/liveview/src/lib.rs

@@ -18,6 +18,8 @@ pub mod adapters {
 
 pub use adapters::*;
 
+#[cfg(all(feature = "hot-reload", debug_assertions))]
+mod hot_reload;
 pub mod pool;
 use futures_util::{SinkExt, StreamExt};
 pub use pool::*;

+ 18 - 0
packages/liveview/src/pool.rs

@@ -103,6 +103,13 @@ pub async fn run<T>(
 where
     T: Send + 'static,
 {
+    #[cfg(all(feature = "hot-reload", debug_assertions))]
+    let mut hot_reload_rx = {
+        let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
+        crate::hot_reload::init(tx);
+        rx
+    };
+
     let mut vdom = VirtualDom::new_with_props(app, props);
 
     // todo: use an efficient binary packed format for this
@@ -122,6 +129,11 @@ where
     }
 
     loop {
+        #[cfg(all(feature = "hot-reload", debug_assertions))]
+        let hot_reload_wait = hot_reload_rx.recv();
+        #[cfg(not(all(feature = "hot-reload", debug_assertions)))]
+        let hot_reload_wait = std::future::pending();
+
         tokio::select! {
             // poll any futures or suspense
             _ = vdom.wait_for_work() => {}
@@ -138,6 +150,12 @@ where
                     None => return Ok(()),
                 }
             }
+
+            new_template = hot_reload_wait => {
+                if let Some(new_template) = new_template {
+                    vdom.replace_template(new_template);
+                }
+            }
         }
 
         let edits = vdom