Evan Almloff 2 rokov pred
rodič
commit
c5ac7698fa
4 zmenil súbory, kde vykonal 133 pridanie a 181 odobranie
  1. 2 2
      Cargo.lock
  2. 3 3
      Cargo.toml
  3. 95 89
      src/server/hot_reload.rs
  4. 33 87
      src/server/mod.rs

+ 2 - 2
Cargo.lock

@@ -2374,9 +2374,9 @@ dependencies = [
 
 [[package]]
 name = "serde_repr"
-version = "0.1.9"
+version = "0.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca"
+checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
 dependencies = [
  "proc-macro2",
  "quote",

+ 3 - 3
Cargo.toml

@@ -73,9 +73,9 @@ mlua = { version = "0.8.1", features = [
 ] }
 ctrlc = "3.2.3"
 # dioxus-rsx = "0.0.1"
-dioxus-rsx = { path = "/home/evan/Desktop/github/dioxus/packages/rsx" }
-dioxus-html = { path = "/home/evan/Desktop/github/dioxus/packages/html" }
-dioxus-core = { path = "/home/evan/Desktop/github/dioxus/packages/core" }
+dioxus-rsx = { path = "c:/users/Desktop/github/dioxus/packages/rsx" }
+dioxus-html = { path = "c:/users//Desktop/github/dioxus/packages/html" }
+dioxus-core = { path = "c:/users//Desktop/github/dioxus/packages/core" }
 
 [[bin]]
 path = "src/main.rs"

+ 95 - 89
src/server/hot_reload.rs

@@ -2,6 +2,7 @@ use axum::{
     extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade},
     response::IntoResponse,
 };
+use dioxus_rsx::CallBody;
 // use dioxus_rsx::try_parse_template;
 
 use std::{path::PathBuf, sync::Arc};
@@ -10,6 +11,7 @@ use super::BuildManager;
 pub use crate::hot_reload::{find_rsx, DiffResult};
 use crate::CrateConfig;
 use dioxus_core::Template;
+use dioxus_html::HtmlCtx;
 pub use proc_macro2::TokenStream;
 pub use std::collections::HashMap;
 pub use std::sync::Mutex;
@@ -20,45 +22,101 @@ pub use syn::__private::ToTokens;
 use syn::spanned::Spanned;
 use tokio::sync::broadcast;
 
+pub(crate) enum UpdateResult {
+    UpdatedRsx(Vec<Template<'static>>),
+    NeedsRebuild,
+}
+
+pub(crate) fn update_rsx(
+    path: &Path,
+    crate_dir: &Path,
+    src: String,
+    file_map: &mut FileMap,
+) -> UpdateResult {
+    if let Ok(syntax) = syn::parse_file(&src) {
+        if let Some((old_src, template_slot)) = file_map.map.get_mut(path) {
+            if let Ok(old) = syn::parse_file(old_src) {
+                match find_rsx(&syntax, &old) {
+                    DiffResult::CodeChanged => {
+                        file_map.map.insert(path.to_path_buf(), (src, None));
+                    }
+                    DiffResult::RsxChanged(changed) => {
+                        log::info!("🪁 reloading rsx");
+                        let mut messages: Vec<Template<'static>> = Vec::new();
+                        for (old, new) in changed.into_iter() {
+                            let old_start = old.span().start();
+
+                            if let (Ok(old_call_body), Ok(new_call_body)) = (
+                                syn::parse2::<CallBody<HtmlCtx>>(old.tokens),
+                                syn::parse2::<CallBody<HtmlCtx>>(new),
+                            ) {
+                                if let Ok(file) = path.strip_prefix(crate_dir) {
+                                    let line = old_start.line;
+                                    let column = old_start.column + 1;
+                                    let location = file.display().to_string()
+                                        + ":"
+                                        + &line.to_string()
+                                        + ":"
+                                        + &column.to_string();
+
+                                    if let Some(template) = new_call_body.update_template(
+                                        Some(old_call_body),
+                                        Box::leak(location.into_boxed_str()),
+                                    ) {
+                                        *template_slot = Some(template);
+                                        messages.push(template);
+                                    } else {
+                                        return UpdateResult::NeedsRebuild;
+                                    }
+                                }
+                            }
+                        }
+                        return UpdateResult::UpdatedRsx(messages);
+                    }
+                }
+            }
+        } else {
+            // if this is a new file, rebuild the project
+            *file_map = FileMap::new(crate_dir.to_path_buf());
+        }
+    }
+    UpdateResult::NeedsRebuild
+}
+
 pub struct HotReloadState {
     pub messages: broadcast::Sender<Template<'static>>,
     pub build_manager: Arc<BuildManager>,
-    pub last_file_rebuild: Arc<Mutex<FileMap>>,
+    pub file_map: Arc<Mutex<FileMap>>,
     pub watcher_config: CrateConfig,
 }
 
 pub struct FileMap {
-    pub map: HashMap<PathBuf, String>,
-    pub last_updated_time: std::time::SystemTime,
+    pub map: HashMap<PathBuf, (String, Option<Template<'static>>)>,
 }
 
 impl FileMap {
     pub fn new(path: PathBuf) -> Self {
         log::info!("🔮 Searching files for changes since last compile...");
-        fn find_rs_files(root: PathBuf) -> io::Result<HashMap<PathBuf, String>> {
+        fn find_rs_files(
+            root: PathBuf,
+        ) -> io::Result<HashMap<PathBuf, (String, Option<Template<'static>>)>> {
             let mut files = HashMap::new();
             if root.is_dir() {
-                for entry in fs::read_dir(root)? {
-                    if let Ok(entry) = entry {
-                        let path = entry.path();
-                        files.extend(find_rs_files(path)?);
-                    }
+                for entry in (fs::read_dir(root)?).flatten() {
+                    let path = entry.path();
+                    files.extend(find_rs_files(path)?);
                 }
-            } else {
-                if root.extension().map(|s| s.to_str()).flatten() == Some("rs") {
-                    if let Ok(mut file) = File::open(root.clone()) {
-                        let mut src = String::new();
-                        file.read_to_string(&mut src).expect("Unable to read file");
-                        files.insert(root, src);
-                    }
+            } else if root.extension().and_then(|s| s.to_str()) == Some("rs") {
+                if let Ok(mut file) = File::open(root.clone()) {
+                    let mut src = String::new();
+                    file.read_to_string(&mut src).expect("Unable to read file");
+                    files.insert(root, (src, None));
                 }
             }
             Ok(files)
         }
 
-        let last_updated_time = SystemTime::now();
         let result = Self {
-            last_updated_time,
             map: find_rs_files(path).unwrap(),
         };
         // log::info!("Files updated");
@@ -75,82 +133,28 @@ pub async fn hot_reload_handler(
         log::info!("🔥 Hot Reload WebSocket connected");
         {
             // update any rsx calls that changed before the websocket connected.
-            // let mut messages = Vec::new();
-
             {
                 log::info!("🔮 Finding updates since last compile...");
-                let handle = state.last_file_rebuild.lock().unwrap();
-                let update_time = handle.last_updated_time.clone();
-                for (k, v) in handle.map.iter() {
-                    let mut file = File::open(k).unwrap();
-                    if let Ok(md) = file.metadata() {
-                        if let Ok(time) = md.modified() {
-                            if time < update_time {
-                                continue;
-                            }
-                        }
-                    }
-                    let mut new_str = String::new();
-                    file.read_to_string(&mut new_str)
-                        .expect("Unable to read file");
-                    if let Ok(new_file) = syn::parse_file(&new_str) {
-                        if let Ok(old_file) = syn::parse_file(&v) {
-                            if let DiffResult::RsxChanged(changed) = find_rsx(&new_file, &old_file)
-                            {
-                                for (old, new) in changed.into_iter() {
-                                    // let hr = get_location(
-                                    //     &state.watcher_config.crate_dir,
-                                    //     k,
-                                    //     old.to_token_stream(),
-                                    // );
-                                    // get the original source code to preserve whitespace
-                                    let span = new.span();
-                                    let start = span.start();
-                                    let end = span.end();
-                                    let mut lines: Vec<_> = new_str
-                                        .lines()
-                                        .skip(start.line - 1)
-                                        .take(end.line - start.line + 1)
-                                        .collect();
-                                    if let Some(first) = lines.first_mut() {
-                                        *first = first.split_at(start.column).1;
-                                    }
-                                    if let Some(last) = lines.last_mut() {
-                                        // if there is only one line the start index of last line will be the start of the rsx!, not the start of the line
-                                        if start.line == end.line {
-                                            *last = last.split_at(end.column - start.column).0;
-                                        } else {
-                                            *last = last.split_at(end.column).0;
-                                        }
-                                    }
-                                    let rsx = lines.join("\n");
-
-                                    // let old_dyn_ctx = try_parse_template(
-                                    //     &format!("{}", old.tokens),
-                                    //     hr.to_owned(),
-                                    //     None,
-                                    // )
-                                    // .map(|(_, old_dyn_ctx)| old_dyn_ctx);
-                                    // if let Ok((template, _)) =
-                                    //     try_parse_template(&rsx, hr.to_owned(), old_dyn_ctx.ok())
-                                    // {
-                                    //     // messages.push(SetTemplateMsg(TemplateId(hr), template));
-                                    // }
-                                }
-                            }
-                        }
+                let templates: Vec<_> = {
+                    state
+                        .file_map
+                        .lock()
+                        .unwrap()
+                        .map
+                        .values()
+                        .filter_map(|(_, template_slot)| *template_slot)
+                        .collect()
+                };
+                for template in templates {
+                    if socket
+                        .send(Message::Text(serde_json::to_string(&template).unwrap()))
+                        .await
+                        .is_err()
+                    {
+                        return;
                     }
                 }
             }
-            // for msg in messages {
-            //     if socket
-            //         .send(Message::Text(serde_json::to_string(&msg).unwrap()))
-            //         .await
-            //         .is_err()
-            //     {
-            //         return;
-            //     }
-            // }
             log::info!("finished");
         }
 
@@ -158,11 +162,13 @@ pub async fn hot_reload_handler(
         let hot_reload_handle = tokio::spawn(async move {
             loop {
                 if let Ok(rsx) = rx.recv().await {
+                    println!("sending");
                     if socket
                         .send(Message::Text(serde_json::to_string(&rsx).unwrap()))
                         .await
                         .is_err()
                     {
+                        println!("error sending");
                         break;
                     };
                 }

+ 33 - 87
src/server/mod.rs

@@ -79,7 +79,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
 
     let dist_path = config.out_dir.clone();
     let (reload_tx, _) = broadcast::channel(100);
-    let last_file_rebuild = Arc::new(Mutex::new(FileMap::new(config.crate_dir.clone())));
+    let file_map = Arc::new(Mutex::new(FileMap::new(config.crate_dir.clone())));
     let build_manager = Arc::new(BuildManager {
         config: config.clone(),
         reload_tx: reload_tx.clone(),
@@ -88,7 +88,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
     let hot_reload_state = Arc::new(HotReloadState {
         messages: hot_reload_tx.clone(),
         build_manager: build_manager.clone(),
-        last_file_rebuild: last_file_rebuild.clone(),
+        file_map: file_map.clone(),
         watcher_config: config.clone(),
     });
 
@@ -97,8 +97,6 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
         update: reload_tx.clone(),
     });
 
-    let mut last_update_time = chrono::Local::now().timestamp();
-
     // file watcher: check file change
     let allow_watch_path = config
         .dioxus_config
@@ -109,100 +107,50 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
         .unwrap_or_else(|| vec![PathBuf::from("src")]);
 
     let watcher_config = config.clone();
+    let mut last_update_time = chrono::Local::now().timestamp();
+
     let mut watcher = RecommendedWatcher::new(
         move |evt: notify::Result<notify::Event>| {
             let config = watcher_config.clone();
+            // Give time for the change to take effect before reading the file
+            std::thread::sleep(std::time::Duration::from_millis(100));
             if chrono::Local::now().timestamp() > last_update_time {
-                // Give time for the change to take effect before reading the file
-                std::thread::sleep(std::time::Duration::from_millis(100));
-                let mut updated = false;
                 if let Ok(evt) = evt {
+                    println!("{:?}", evt);
                     let mut messages: Vec<Template<'static>> = Vec::new();
-                    let mut needs_rebuild = false;
                     for path in evt.paths.clone() {
-                        if path.extension().map(|p| p.to_str()).flatten() != Some("rs") {
+                        if path.extension().and_then(|p| p.to_str()) != Some("rs") {
                             continue;
                         }
                         let mut file = File::open(path.clone()).unwrap();
                         let mut src = String::new();
                         file.read_to_string(&mut src).expect("Unable to read file");
                         // find changes to the rsx in the file
-                        if let Ok(syntax) = syn::parse_file(&src) {
-                            let mut last_file_rebuild = last_file_rebuild.lock().unwrap();
-                            if let Some(old_str) = last_file_rebuild.map.get(&path) {
-                                if let Ok(old) = syn::parse_file(&old_str) {
-                                    updated = true;
-                                    match find_rsx(&syntax, &old) {
-                                        DiffResult::CodeChanged => {
-                                            needs_rebuild = true;
-                                            last_file_rebuild.map.insert(path, src);
-                                        }
-                                        DiffResult::RsxChanged(changed) => {
-                                            log::info!("🪁 reloading rsx");
-                                            for (old, new) in changed.into_iter() {
-                                                let old_start = old.span().start();
-
-                                                if let (Ok(old_call_body), Ok(new_call_body)) = (
-                                                    syn::parse2::<CallBody>(old.tokens),
-                                                    syn::parse2::<CallBody>(new),
-                                                ) {
-                                                    let spndbg = format!(
-                                                        "{:?}",
-                                                        old_call_body.roots[0].span()
-                                                    );
-                                                    let root_col =
-                                                        spndbg[9..].split("..").next().unwrap();
-                                                    if let Ok(file) = path.strip_prefix(&crate_dir)
-                                                    {
-                                                        let line = old_start.line;
-                                                        let column = old_start.column;
-                                                        let location = file.display().to_string()
-                                                            + ":"
-                                                            + &line.to_string()
-                                                            + ":"
-                                                            + &column.to_string()
-                                                            + ":"
-                                                            + root_col;
-
-                                                        if let Some(template) = new_call_body
-                                                            .update_template(
-                                                                Some(old_call_body),
-                                                                Box::leak(
-                                                                    location.into_boxed_str(),
-                                                                ),
-                                                            )
-                                                        {
-                                                            messages.push(template);
-                                                        } else {
-                                                            needs_rebuild = true;
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
+                        let mut map = file_map.lock().unwrap();
+
+                        match update_rsx(&path, &crate_dir, src, &mut map) {
+                            UpdateResult::UpdatedRsx(msgs) => {
+                                println!("{msgs:#?}");
+                                messages.extend(msgs);
+                            }
+                            UpdateResult::NeedsRebuild => {
+                                match build_manager.rebuild() {
+                                    Ok(res) => {
+                                        print_console_info(
+                                            port,
+                                            &config,
+                                            PrettierOptions {
+                                                changed: evt.paths,
+                                                warnings: res.warnings,
+                                                elapsed_time: res.elapsed_time,
+                                            },
+                                        );
+                                    }
+                                    Err(err) => {
+                                        log::error!("{}", err);
                                     }
                                 }
-                            } else {
-                                // if this is a new file, rebuild the project
-                                *last_file_rebuild = FileMap::new(crate_dir.clone());
-                            }
-                        }
-                    }
-                    if needs_rebuild {
-                        match build_manager.rebuild() {
-                            Ok(res) => {
-                                print_console_info(
-                                    port,
-                                    &config,
-                                    PrettierOptions {
-                                        changed: evt.paths,
-                                        warnings: res.warnings,
-                                        elapsed_time: res.elapsed_time,
-                                    },
-                                );
-                            }
-                            Err(err) => {
-                                log::error!("{}", err);
+                                return;
                             }
                         }
                     }
@@ -210,9 +158,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
                         let _ = hot_reload_tx.send(msg);
                     }
                 }
-                if updated {
-                    last_update_time = chrono::Local::now().timestamp();
-                }
+                last_update_time = chrono::Local::now().timestamp();
             }
         },
         notify::Config::default(),
@@ -274,7 +220,7 @@ pub async fn startup_hot_reload(port: u16, config: CrateConfig) -> Result<()> {
                 Ok(response)
             },
         )
-        .service(ServeDir::new((&config.crate_dir).join(&dist_path)));
+        .service(ServeDir::new(config.crate_dir.join(&dist_path)));
 
     let router = Router::new()
         .route("/_dioxus/ws", get(ws_handler))