Browse Source

add depinfo watcher

Jonathan Kelley 5 days ago
parent
commit
16e6646b84

+ 17 - 1
packages/cli/src/build/builder.rs

@@ -607,8 +607,12 @@ impl AppBuilder {
         let triple = self.build.triple.clone();
         let asset_dir = self.build.asset_dir();
 
+        // Hotpatch asset!() calls
         for bundled in res.assets.assets() {
-            let original_artifacts = self.artifacts.as_mut().unwrap();
+            let original_artifacts = self
+                .artifacts
+                .as_mut()
+                .context("No artifacts to hotpatch")?;
 
             if original_artifacts.assets.contains(bundled) {
                 continue;
@@ -634,6 +638,18 @@ impl AppBuilder {
             }
         }
 
+        // Make sure to add `include!()` calls to the watcher so we can watch changes as they evolve
+        for file in res.depinfo.files.iter() {
+            let original_artifacts = self
+                .artifacts
+                .as_mut()
+                .context("No artifacts to hotpatch")?;
+
+            if !original_artifacts.depinfo.files.contains(file) {
+                original_artifacts.depinfo.files.push(file.clone());
+            }
+        }
+
         tracing::debug!("Patching {} -> {}", original.display(), new.display());
 
         let mut jump_table = crate::build::create_jump_table(&new, &triple, cache)?;

+ 4 - 0
packages/cli/src/build/request.rs

@@ -322,6 +322,7 @@ use crate::{
 };
 use anyhow::{bail, Context};
 use cargo_metadata::diagnostic::Diagnostic;
+use depinfo::RustcDepInfo;
 use dioxus_cli_config::format_base_path_meta_element;
 use dioxus_cli_config::{APP_TITLE_ENV, ASSET_ROOT_ENV};
 use dioxus_cli_opt::{process_file_to, AssetManifest};
@@ -443,6 +444,7 @@ pub struct BuildArtifacts {
     pub(crate) assets: AssetManifest,
     pub(crate) mode: BuildMode,
     pub(crate) patch_cache: Option<Arc<HotpatchModuleCache>>,
+    pub(crate) depinfo: RustcDepInfo,
 }
 
 impl BuildRequest {
@@ -986,6 +988,7 @@ impl BuildRequest {
         let time_end = SystemTime::now();
         let mode = ctx.mode.clone();
         let platform = self.platform;
+        let depinfo = RustcDepInfo::from_file(&exe.with_extension("d")).unwrap_or_default();
 
         tracing::debug!(
             "Build completed successfully in {}us: {:?}",
@@ -1001,6 +1004,7 @@ impl BuildRequest {
             time_start,
             assets,
             mode,
+            depinfo,
             patch_cache: None,
         })
     }

+ 14 - 3
packages/cli/src/serve/runner.rs

@@ -362,9 +362,10 @@ impl AppServer {
         for path in files {
             // for various assets that might be linked in, we just try to hotreloading them forcefully
             // That is, unless they appear in an include! macro, in which case we need to a full rebuild....
-            let Some(ext) = path.extension().and_then(|v| v.to_str()) else {
-                continue;
-            };
+            let ext = path
+                .extension()
+                .and_then(|v| v.to_str())
+                .unwrap_or_default();
 
             // If it's an asset, we want to hotreload it
             // todo(jon): don't hardcode this here
@@ -465,6 +466,16 @@ impl AppServer {
                     }
                 }
             }
+
+            // If it's not a rust file, then it might be depended on via include! or similar
+            if ext != "rs" {
+                if let Some(artifacts) = self.client.artifacts.as_ref() {
+                    if artifacts.depinfo.files.contains(path) {
+                        needs_full_rebuild = true;
+                        break;
+                    }
+                }
+            }
         }
 
         // todo - we need to distinguish between hotpatchable rebuilds and true full rebuilds.

+ 8 - 2
packages/depinfo/src/lib.rs

@@ -3,7 +3,7 @@
 //! Used by the hot-reloading engine and other libraries to provide higher quality dependency analysis
 //! for the user's project.
 
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 
 #[non_exhaustive]
 #[derive(Debug, thiserror::Error)]
@@ -18,7 +18,7 @@ pub enum DepInfoParseError {
 }
 
 #[non_exhaustive]
-#[derive(Default, Debug)]
+#[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct RustcDepInfo {
     /// The list of files that the main target in the dep-info file depends on.
     pub files: Vec<PathBuf>,
@@ -42,6 +42,12 @@ impl std::str::FromStr for RustcDepInfo {
 }
 
 impl RustcDepInfo {
+    pub fn from_file(path: &Path) -> Result<RustcDepInfo, DepInfoParseError> {
+        let contents =
+            std::fs::read_to_string(path).map_err(|_| DepInfoParseError::MalformedInput)?;
+        RustcDepInfo::new(&contents)
+    }
+
     /// Parse the `.d` dep-info file generated by rustc.
     pub fn new(contents: &str) -> Result<RustcDepInfo, DepInfoParseError> {
         let mut ret = RustcDepInfo::default();