Explorar o código

fix desktop hot reloading

Evan Almloff hai 1 ano
pai
achega
2c1c147828

+ 1 - 1
examples/simple_desktop.rs

@@ -48,7 +48,7 @@ fn BlogList(cx: Scope) -> Element {
 
 fn BlogPost(cx: Scope) -> Element {
     let Some(id) = use_route(cx).segment("id") else {
-        return cx.render(rsx! { div { "No blog post id" } })
+        return cx.render(rsx! { div { "No blog post id" } });
     };
 
     log::debug!("rendering blog post {}", id);

+ 1 - 0
packages/cli/src/builder.rs

@@ -364,6 +364,7 @@ pub fn build_desktop(config: &CrateConfig, _is_serve: bool) -> Result<BuildResul
                 .display()
         );
     }
+    println!("build desktop done");
 
     Ok(BuildResult {
         warnings: vec![],

+ 1 - 15
packages/cli/src/cli/serve.rs

@@ -57,21 +57,7 @@ impl Serve {
                     .await?;
             }
             cfg::Platform::Desktop => {
-                crate::builder::build_desktop(&crate_config, true)?;
-
-                match &crate_config.executable {
-                    crate::ExecutableType::Binary(name)
-                    | crate::ExecutableType::Lib(name)
-                    | crate::ExecutableType::Example(name) => {
-                        let mut file = crate_config.out_dir.join(name);
-                        if cfg!(windows) {
-                            file.set_extension("exe");
-                        }
-                        Command::new(file.to_str().unwrap())
-                            .stdout(Stdio::inherit())
-                            .output()?;
-                    }
-                }
+                server::desktop::startup(crate_config.clone()).await?;
             }
         }
         Ok(())

+ 24 - 14
packages/cli/src/server/desktop/mod.rs

@@ -3,7 +3,7 @@ use crate::{
     serve::Serve,
     server::{
         output::{print_console_info, PrettierOptions, WebServerInfo},
-        setup_file_watcher, setup_file_watcher_hot_reload, BuildManager,
+        setup_file_watcher, setup_file_watcher_hot_reload,
     },
     BuildResult, CrateConfig, Result,
 };
@@ -72,7 +72,15 @@ pub async fn serve_default(config: CrateConfig) -> Result<()> {
 
     // We got to own watcher so that it exists for the duration of serve
     // Otherwise full reload won't work.
-    let _watcher = setup_file_watcher(crate::cfg::Platform::Desktop, &config, None, None).await?;
+    let _watcher = setup_file_watcher(
+        {
+            let config = config.clone();
+            move || start_desktop(&config)
+        },
+        &config,
+        None,
+    )
+    .await?;
 
     // Print serve info
     print_console_info(
@@ -107,15 +115,13 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
     }
 
     let file_map = Arc::new(Mutex::new(map));
-    let build_manager = Arc::new(BuildManager {
-        platform: crate::cfg::Platform::Web,
-        config: config.clone(),
-        reload_tx: None,
-    });
 
     let (hot_reload_tx, mut hot_reload_rx) = broadcast::channel(100);
 
     // States
+    // The open interprocess sockets
+    let channels = Arc::new(Mutex::new(Vec::new()));
+
     // Setup file watcher
     // We got to own watcher so that it exists for the duration of serve
     // Otherwise hot reload won't work.
@@ -123,7 +129,17 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
         &config,
         hot_reload_tx,
         file_map.clone(),
-        build_manager,
+        {
+            let config = config.clone();
+
+            let channels = channels.clone();
+            move || {
+                for channel in &mut *channels.lock().unwrap() {
+                    send_msg(HotReloadMsg::Shutdown, channel);
+                }
+                start_desktop(&config)
+            }
+        },
         None,
     )
     .await?;
@@ -153,8 +169,6 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
         }
     }
 
-    let channels = Arc::new(Mutex::new(Vec::new()));
-
     match LocalSocketListener::bind("@dioxusin") {
         Ok(local_socket_stream) => {
             let aborted = Arc::new(Mutex::new(false));
@@ -196,10 +210,6 @@ pub async fn serve_hot_reload(config: CrateConfig) -> Result<()> {
                 }
             });
 
-            // for channel in &mut *channels.lock().unwrap() {
-            //     send_msg(HotReloadMsg::Shutdown, channel);
-            // }
-
             while let Ok(template) = hot_reload_rx.recv().await {
                 let channels = &mut *channels.lock().unwrap();
                 let mut i = 0;

+ 7 - 46
packages/cli/src/server/mod.rs

@@ -39,18 +39,11 @@ pub mod desktop;
 pub mod web;
 
 /// Sets up a file watcher
-async fn setup_file_watcher(
-    platform: Platform,
+async fn setup_file_watcher<F: Fn() -> Result<BuildResult> + Send + 'static>(
+    build_with: F,
     config: &CrateConfig,
-    reload_tx: Option<Sender<()>>,
     web_info: Option<WebServerInfo>,
 ) -> Result<RecommendedWatcher> {
-    let build_manager = BuildManager {
-        platform,
-        config: config.clone(),
-        reload_tx,
-    };
-
     let mut last_update_time = chrono::Local::now().timestamp();
 
     // file watcher: check file change
@@ -67,7 +60,7 @@ async fn setup_file_watcher(
         let config = watcher_config.clone();
         if let Ok(e) = info {
             if chrono::Local::now().timestamp() > last_update_time {
-                match build_manager.rebuild() {
+                match build_with() {
                     Ok(res) => {
                         last_update_time = chrono::Local::now().timestamp();
 
@@ -108,11 +101,11 @@ async fn setup_file_watcher(
 
 // Todo: reduce duplication and merge with setup_file_watcher()
 /// Sets up a file watcher with hot reload
-async fn setup_file_watcher_hot_reload(
+async fn setup_file_watcher_hot_reload<F: Fn() -> Result<BuildResult> + Send + 'static>(
     config: &CrateConfig,
     hot_reload_tx: Sender<Template<'static>>,
     file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
-    build_manager: Arc<BuildManager>,
+    build_with: F,
     web_info: Option<WebServerInfo>,
 ) -> Result<RecommendedWatcher> {
     // file watcher: check file change
@@ -138,7 +131,7 @@ async fn setup_file_watcher_hot_reload(
                     for path in evt.paths.clone() {
                         // if this is not a rust file, rebuild the whole project
                         if path.extension().and_then(|p| p.to_str()) != Some("rs") {
-                            match build_manager.rebuild() {
+                            match build_with() {
                                 Ok(res) => {
                                     print_console_info(
                                         &config,
@@ -164,7 +157,7 @@ async fn setup_file_watcher_hot_reload(
                                 messages.extend(msgs);
                             }
                             Ok(UpdateResult::NeedsRebuild) => {
-                                match build_manager.rebuild() {
+                                match build_with() {
                                     Ok(res) => {
                                         print_console_info(
                                             &config,
@@ -209,35 +202,3 @@ async fn setup_file_watcher_hot_reload(
 
     Ok(watcher)
 }
-
-pub struct BuildManager {
-    platform: Platform,
-    config: CrateConfig,
-    reload_tx: Option<broadcast::Sender<()>>,
-}
-
-impl BuildManager {
-    fn rebuild(&self) -> Result<BuildResult> {
-        log::info!("🪁 Rebuild project");
-        match self.platform {
-            Platform::Web => {
-                let result = builder::build(&self.config, true)?;
-                // change the websocket reload state to true;
-                // the page will auto-reload.
-                if self
-                    .config
-                    .dioxus_config
-                    .web
-                    .watcher
-                    .reload_html
-                    .unwrap_or(false)
-                {
-                    let _ = Serve::regen_dev_page(&self.config);
-                }
-                let _ = self.reload_tx.as_ref().map(|tx| tx.send(()));
-                Ok(result)
-            }
-            Platform::Desktop => start_desktop(&self.config),
-        }
-    }
-}

+ 0 - 2
packages/cli/src/server/web/hot_reload.rs

@@ -10,12 +10,10 @@ use dioxus_html::HtmlCtx;
 use dioxus_rsx::hot_reload::FileMap;
 use tokio::sync::broadcast;
 
-use super::BuildManager;
 use crate::CrateConfig;
 
 pub struct HotReloadState {
     pub messages: broadcast::Sender<Template<'static>>,
-    pub build_manager: Arc<BuildManager>,
     pub file_map: Arc<Mutex<FileMap<HtmlCtx>>>,
     pub watcher_config: CrateConfig,
 }

+ 28 - 10
packages/cli/src/server/web/mod.rs

@@ -3,7 +3,7 @@ use crate::{
     serve::Serve,
     server::{
         output::{print_console_info, PrettierOptions, WebServerInfo},
-        setup_file_watcher, setup_file_watcher_hot_reload, BuildManager,
+        setup_file_watcher, setup_file_watcher_hot_reload,
     },
     BuildResult, CrateConfig, Result,
 };
@@ -86,9 +86,12 @@ pub async fn serve_default(
     // We got to own watcher so that it exists for the duration of serve
     // Otherwise full reload won't work.
     let _watcher = setup_file_watcher(
-        crate::cfg::Platform::Web,
+        {
+            let config = config.clone();
+            let reload_tx = reload_tx.clone();
+            move || build(&config, &reload_tx)
+        },
         &config,
-        Some(reload_tx.clone()),
         Some(WebServerInfo {
             ip: ip.clone(),
             port,
@@ -148,18 +151,12 @@ pub async fn serve_hot_reload(
     }
 
     let file_map = Arc::new(Mutex::new(map));
-    let build_manager = Arc::new(BuildManager {
-        platform: crate::cfg::Platform::Web,
-        config: config.clone(),
-        reload_tx: Some(reload_tx.clone()),
-    });
 
     let hot_reload_tx = broadcast::channel(100).0;
 
     // States
     let hot_reload_state = Arc::new(HotReloadState {
         messages: hot_reload_tx.clone(),
-        build_manager: build_manager.clone(),
         file_map: file_map.clone(),
         watcher_config: config.clone(),
     });
@@ -175,7 +172,11 @@ pub async fn serve_hot_reload(
         &config,
         hot_reload_tx,
         file_map,
-        build_manager,
+        {
+            let config = config.clone();
+            let reload_tx = reload_tx.clone();
+            move || build(&config, &reload_tx)
+        },
         Some(WebServerInfo {
             ip: ip.clone(),
             port,
@@ -473,3 +474,20 @@ async fn ws_handler(
         reload_watcher.await.unwrap();
     })
 }
+
+fn build(config: &CrateConfig, reload_tx: &Sender<()>) -> Result<BuildResult> {
+    let result = builder::build(&config, true)?;
+    // change the websocket reload state to true;
+    // the page will auto-reload.
+    if config
+        .dioxus_config
+        .web
+        .watcher
+        .reload_html
+        .unwrap_or(false)
+    {
+        let _ = Serve::regen_dev_page(&config);
+    }
+    let _ = reload_tx.send(());
+    Ok(result)
+}

+ 1 - 1
packages/fullstack/src/adapters/salvo_adapter.rs

@@ -378,7 +378,7 @@ impl ServerFnHandler {
             .to_vec()
             .into();
         let body = hyper::body::to_bytes(req.body_mut().unwrap()).await;
-        let Ok(body)=body else {
+        let Ok(body) = body else {
             handle_error(body.err().unwrap(), res);
             return;
         };

+ 3 - 4
packages/html/src/events/form.rs

@@ -56,10 +56,9 @@ where
 {
     use serde::Deserialize;
 
-    let Ok(file_engine) =
-        SerializedFileEngine::deserialize(deserializer) else{
-            return Ok(None);
-        };
+    let Ok(file_engine) = SerializedFileEngine::deserialize(deserializer) else {
+        return Ok(None);
+    };
 
     let file_engine = std::sync::Arc::new(file_engine);
     Ok(Some(file_engine))

+ 12 - 4
packages/rink/src/widgets/button.rs

@@ -82,7 +82,9 @@ impl Button {
     fn write_value(&self, rdom: &mut RealDom) {
         if let Some(mut text) = rdom.get_mut(self.text_id) {
             let node_type = text.node_type_mut();
-            let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Text(mut text) = node_type else {
+                panic!("input must be an element")
+            };
             *text.text_mut() = self.value.clone();
         }
     }
@@ -111,7 +113,9 @@ impl CustomElement for Button {
 
     fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
         let node_type = root.node_type();
-        let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
+        let NodeType::Element(el) = &*node_type else {
+            panic!("input must be an element")
+        };
 
         let value = el
             .attributes
@@ -146,7 +150,9 @@ impl CustomElement for Button {
             AttributeMask::All => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     self.update_value_attr(&el);
                     self.update_size_attr(&mut el);
                 }
@@ -155,7 +161,9 @@ impl CustomElement for Button {
             AttributeMask::Some(attrs) => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     if attrs.contains("width") || attrs.contains("height") {
                         self.update_size_attr(&mut el);
                     }

+ 15 - 5
packages/rink/src/widgets/checkbox.rs

@@ -94,14 +94,18 @@ impl CheckBox {
     fn write_value(&self, mut root: NodeMut) {
         let single_char = {
             let node_type = root.node_type_mut();
-            let NodeTypeMut::Element( el) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Element(el) = node_type else {
+                panic!("input must be an element")
+            };
             Self::width(&el) == "1px" || Self::height(&el) == "1px"
         };
         let rdom = root.real_dom_mut();
 
         if let Some(mut text) = rdom.get_mut(self.text_id) {
             let node_type = text.node_type_mut();
-            let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Text(mut text) = node_type else {
+                panic!("input must be an element")
+            };
             let value = if single_char {
                 if self.checked {
                     "☑"
@@ -156,7 +160,9 @@ impl CustomElement for CheckBox {
 
     fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
         let node_type = root.node_type();
-        let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
+        let NodeType::Element(el) = &*node_type else {
+            panic!("input must be an element")
+        };
 
         let value = el
             .attributes
@@ -197,7 +203,9 @@ impl CustomElement for CheckBox {
             AttributeMask::All => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     self.update_value_attr(&el);
                     self.update_size_attr(&mut el);
                     self.update_checked_attr(&el);
@@ -207,7 +215,9 @@ impl CustomElement for CheckBox {
             AttributeMask::Some(attrs) => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     if attrs.contains("width") || attrs.contains("height") {
                         self.update_size_attr(&mut el);
                     }

+ 3 - 1
packages/rink/src/widgets/input.rs

@@ -56,7 +56,9 @@ impl CustomElement for Input {
         }
 
         let node_type = root.node_type();
-        let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
+        let NodeType::Element(el) = &*node_type else {
+            panic!("input must be an element")
+        };
         let input_type = el
             .attributes
             .get(&OwnedAttributeDiscription {

+ 15 - 5
packages/rink/src/widgets/slider.rs

@@ -163,7 +163,9 @@ impl Slider {
 
         if let Some(mut div) = rdom.get_mut(self.pre_cursor_div) {
             let node_type = div.node_type_mut();
-            let NodeTypeMut::Element(mut element) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Element(mut element) = node_type else {
+                panic!("input must be an element")
+            };
             element.set_attribute(
                 OwnedAttributeDiscription {
                     name: "width".to_string(),
@@ -175,7 +177,9 @@ impl Slider {
 
         if let Some(mut div) = rdom.get_mut(self.post_cursor_div) {
             let node_type = div.node_type_mut();
-            let NodeTypeMut::Element(mut element) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Element(mut element) = node_type else {
+                panic!("input must be an element")
+            };
             element.set_attribute(
                 OwnedAttributeDiscription {
                     name: "width".to_string(),
@@ -259,7 +263,9 @@ impl CustomElement for Slider {
 
     fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
         let node_type = root.node_type();
-        let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
+        let NodeType::Element(el) = &*node_type else {
+            panic!("input must be an element")
+        };
 
         let value = el.attributes.get(&OwnedAttributeDiscription {
             name: "value".to_string(),
@@ -390,7 +396,9 @@ impl CustomElement for Slider {
             AttributeMask::All => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     self.update_value_attr(&el);
                     self.update_size_attr(&mut el);
                     self.update_max_attr(&el);
@@ -403,7 +411,9 @@ impl CustomElement for Slider {
             AttributeMask::Some(attrs) => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     if attrs.contains("width") || attrs.contains("height") {
                         self.update_size_attr(&mut el);
                     }

+ 18 - 6
packages/rink/src/widgets/text_like.rs

@@ -143,19 +143,25 @@ impl<C: TextLikeController> TextLike<C> {
 
         if let Some(mut text) = rdom.get_mut(self.pre_cursor_text) {
             let node_type = text.node_type_mut();
-            let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Text(mut text) = node_type else {
+                panic!("input must be an element")
+            };
             *text.text_mut() = self.controller.display_text(text_before_first_cursor);
         }
 
         if let Some(mut text) = rdom.get_mut(self.highlighted_text) {
             let node_type = text.node_type_mut();
-            let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Text(mut text) = node_type else {
+                panic!("input must be an element")
+            };
             *text.text_mut() = self.controller.display_text(text_highlighted);
         }
 
         if let Some(mut text) = rdom.get_mut(self.post_cursor_text) {
             let node_type = text.node_type_mut();
-            let NodeTypeMut::Text(mut text) = node_type else { panic!("input must be an element") };
+            let NodeTypeMut::Text(mut text) = node_type else {
+                panic!("input must be an element")
+            };
             *text.text_mut() = self.controller.display_text(text_after_second_cursor);
         }
 
@@ -288,7 +294,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
 
     fn create(mut root: dioxus_native_core::real_dom::NodeMut) -> Self {
         let node_type = root.node_type();
-        let NodeType::Element(el) = &*node_type else { panic!("input must be an element") };
+        let NodeType::Element(el) = &*node_type else {
+            panic!("input must be an element")
+        };
 
         let value = el
             .attributes
@@ -370,7 +378,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
             AttributeMask::All => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     self.update_value_attr(&el);
                     self.update_size_attr(&mut el);
                     self.update_max_width_attr(&el);
@@ -381,7 +391,9 @@ impl<C: TextLikeController + Send + Sync + Default + 'static> CustomElement for
             AttributeMask::Some(attrs) => {
                 {
                     let node_type = root.node_type_mut();
-                    let NodeTypeMut::Element(mut el) = node_type else { panic!("input must be an element") };
+                    let NodeTypeMut::Element(mut el) = node_type else {
+                        panic!("input must be an element")
+                    };
                     if attrs.contains("width") || attrs.contains("height") {
                         self.update_size_attr(&mut el);
                     }

+ 1 - 1
packages/router/examples/simple_routes.rs

@@ -38,7 +38,7 @@ fn BlogList(cx: Scope) -> Element {
 
 fn BlogPost(cx: Scope) -> Element {
     let Some(id) = use_route(cx).segment("id") else {
-        return cx.render(rsx! { div { "No blog post id" } })
+        return cx.render(rsx! { div { "No blog post id" } });
     };
 
     log::trace!("rendering blog post {}", id);