瀏覽代碼

fix(cli): `dev` config reload (#1172)

* fix(cli): `dev` config reload

* refactor: remove unnecessary mutex on config

* fix: clippy

* fix(cli/core): don't rebuild twice

* fix(core/cli/dev): don't kill app twice

Co-authored-by: Noah Klayman <noahklayman@gmail.com>
Lucas Fernandes Nogueira 4 年之前
父節點
當前提交
eeb46ad585

+ 17 - 10
cli/core/src/build.rs

@@ -52,7 +52,10 @@ impl Build {
 
   pub fn run(self) -> crate::Result<()> {
     let config = get_config(self.config.as_deref())?;
-    let feature = if config.tauri.embedded_server.active {
+    let config_guard = config.lock().unwrap();
+    let config_ = config_guard.as_ref().unwrap();
+
+    let feature = if config_.tauri.embedded_server.active {
       "embedded-server"
     } else {
       "no-server"
@@ -86,22 +89,26 @@ impl Build {
     let tauri_path = tauri_dir();
     set_current_dir(&tauri_path)?;
     set_var("TAURI_DIR", &tauri_path);
-    set_var("TAURI_DIST_DIR", tauri_path.join(&config.build.dist_dir));
+    set_var("TAURI_DIST_DIR", tauri_path.join(&config_.build.dist_dir));
+
+    drop(config_guard);
+    rewrite_manifest(config.clone())?;
 
-    rewrite_manifest(&config)?;
+    let config_guard = config.lock().unwrap();
+    let config_ = config_guard.as_ref().unwrap();
 
-    let index_html_path = PathBuf::from(&config.build.dist_dir).join("index.html");
-    let tauri_html = TauriHtml::new(&config.build.dist_dir, read_to_string(index_html_path)?)
-      .inliner_enabled(config.tauri.inliner.active && !config.tauri.embedded_server.active)
-      .global_tauri(config.build.with_global_tauri)
+    let index_html_path = PathBuf::from(&config_.build.dist_dir).join("index.html");
+    let tauri_html = TauriHtml::new(&config_.build.dist_dir, read_to_string(index_html_path)?)
+      .inliner_enabled(config_.tauri.inliner.active && !config_.tauri.embedded_server.active)
+      .global_tauri(config_.build.with_global_tauri)
       .generate()?;
-    let tauri_index_html_path = PathBuf::from(&config.build.dist_dir).join("index.tauri.html");
+    let tauri_index_html_path = PathBuf::from(&config_.build.dist_dir).join("index.tauri.html");
     let mut tauri_index_html_file = File::create(tauri_index_html_path)?;
     tauri_index_html_file.write_all(tauri_html.as_bytes())?;
 
     let settings = settings_builder.build()?;
 
-    if let Some(before_build) = &config.build.before_build_command {
+    if let Some(before_build) = &config_.build.before_build_command {
       let mut cmd: Option<&str> = None;
       let mut args: Vec<&str> = vec![];
       for token in before_build.split(' ') {
@@ -120,7 +127,7 @@ impl Build {
     }
 
     build_project(&settings)?;
-    if config.tauri.bundle.active {
+    if config_.tauri.bundle.active {
       bundle_project(settings)?;
     }
     Ok(())

+ 62 - 31
cli/core/src/dev.rs

@@ -1,6 +1,6 @@
 use crate::helpers::{
   app_paths::{app_dir, tauri_dir},
-  config::{get as get_config, reload as reload_config, Config},
+  config::{get as get_config, reload as reload_config, ConfigHandle},
   manifest::rewrite_manifest,
   Logger, TauriHtml,
 };
@@ -52,13 +52,19 @@ impl Dev {
   pub fn run(self) -> crate::Result<()> {
     let logger = Logger::new("tauri:dev");
     let tauri_path = tauri_dir();
-    let config = get_config(self.config.as_deref())?;
-    let mut config_mut = config.clone();
+    let merge_config = self.config.clone();
+    let config = get_config(merge_config.as_deref())?;
     let mut _guard = None;
     let mut process: Arc<SharedChild>;
-    let new_dev_path: String;
 
-    if let Some(before_dev) = &config.build.before_dev_command {
+    if let Some(before_dev) = &config
+      .lock()
+      .unwrap()
+      .as_ref()
+      .unwrap()
+      .build
+      .before_dev_command
+    {
       let mut cmd: Option<&str> = None;
       let mut args: Vec<&str> = vec![];
       for token in before_dev.split(' ') {
@@ -77,10 +83,17 @@ impl Dev {
       }
     }
 
-    let running_dev_server = config.build.dev_path.starts_with("http");
-
-    if running_dev_server {
-      let dev_path = Url::parse(&config.build.dev_path)?;
+    let running_dev_server = config
+      .lock()
+      .unwrap()
+      .as_ref()
+      .unwrap()
+      .build
+      .dev_path
+      .starts_with("http");
+
+    let new_dev_path = if running_dev_server {
+      let dev_path = Url::parse(&config.lock().unwrap().as_ref().unwrap().build.dev_path)?;
       let dev_port = dev_path.port().unwrap_or(80);
 
       let timeout = Duration::from_secs(3);
@@ -105,27 +118,33 @@ impl Dev {
 
       logger.log(format!("starting dev proxy on port {}", proxy_port));
       let config_ = config.clone();
-      std::thread::spawn(move || proxy_dev_server(&config_, &proxy_path, proxy_port));
+      std::thread::spawn(move || proxy_dev_server(config_, &proxy_path, proxy_port));
 
-      new_dev_path = format!(
+      format!(
         "http://{}:{}",
         dev_path.host_str().expect("failed to read dev_path host"),
         proxy_port
-      );
+      )
     } else {
-      new_dev_path = tauri_dir()
-        .join(&config.build.dev_path)
+      tauri_dir()
+        .join(&config.lock().unwrap().as_ref().unwrap().build.dev_path)
         .to_string_lossy()
-        .to_string();
-    }
+        .to_string()
+    };
 
-    config_mut.build.dev_path = new_dev_path.clone();
+    (*config.lock().unwrap()).as_mut().unwrap().build.dev_path = new_dev_path.to_string();
 
     set_var("TAURI_DIR", &tauri_path);
-    set_var("TAURI_DIST_DIR", tauri_path.join(&config.build.dist_dir));
-    set_var("TAURI_CONFIG", serde_json::to_string(&config_mut)?);
+    set_var(
+      "TAURI_DIST_DIR",
+      tauri_path.join(&config.lock().unwrap().as_ref().unwrap().build.dist_dir),
+    );
+    set_var(
+      "TAURI_CONFIG",
+      serde_json::to_string(&*config.lock().unwrap())?,
+    );
 
-    rewrite_manifest(&config)?;
+    rewrite_manifest(config.clone())?;
 
     let (child_wait_tx, child_wait_rx) = channel();
     let child_wait_rx = Arc::new(Mutex::new(child_wait_rx));
@@ -134,13 +153,20 @@ impl Dev {
 
     let (tx, rx) = channel();
 
-    let mut watcher = watcher(tx, Duration::from_secs(2)).unwrap();
+    let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
     watcher.watch(tauri_path.join("src"), RecursiveMode::Recursive)?;
     watcher.watch(tauri_path.join("Cargo.toml"), RecursiveMode::Recursive)?;
     watcher.watch(tauri_path.join("tauri.conf.json"), RecursiveMode::Recursive)?;
     if !running_dev_server {
       watcher.watch(
-        config_mut.build.dev_path.to_string(),
+        config
+          .lock()
+          .unwrap()
+          .as_ref()
+          .unwrap()
+          .build
+          .dev_path
+          .to_string(),
         RecursiveMode::Recursive,
       )?;
     }
@@ -156,16 +182,19 @@ impl Dev {
         };
 
         if let Some(event_path) = event_path {
-          let _ = child_wait_tx.send(true);
-          process.kill()?;
           if event_path.file_name() == Some(OsStr::new("tauri.conf.json")) {
-            config_mut = reload_config(Some(&serde_json::to_string(&config_mut)?))?.clone();
-            rewrite_manifest(&config_mut)?;
-            config_mut.build.dev_path = new_dev_path.clone();
-            set_var("TAURI_CONFIG", serde_json::to_string(&config_mut)?);
+            reload_config(merge_config.as_deref())?;
+            (*config.lock().unwrap()).as_mut().unwrap().build.dev_path = new_dev_path.to_string();
+            rewrite_manifest(config.clone())?;
+            set_var("TAURI_CONFIG", serde_json::to_string(&*config)?);
+          } else {
+            // When tauri.conf.json is changed, rewrite_manifest will be called
+            // which will trigger the watcher again
+            // So the app should only be started when a file other than tauri.conf.json is changed
+            let _ = child_wait_tx.send(true);
+            process.kill()?;
+            process = self.start_app(child_wait_rx.clone());
           }
-
-          process = self.start_app(child_wait_rx.clone());
         }
       }
     }
@@ -196,7 +225,7 @@ impl Dev {
   }
 }
 
-fn proxy_dev_server(config: &Config, dev_path: &Url, dev_port: u16) -> crate::Result<()> {
+fn proxy_dev_server(config: ConfigHandle, dev_path: &Url, dev_port: u16) -> crate::Result<()> {
   let server_url = format!(
     "{}:{}",
     dev_path.host_str().expect("failed to read dev_path host"),
@@ -218,6 +247,8 @@ fn proxy_dev_server(config: &Config, dev_path: &Url, dev_port: u16) -> crate::Re
     }
 
     if request_url == "/" {
+      let config_guard = config.lock().unwrap();
+      let config = config_guard.as_ref().unwrap();
       let response = request_builder.send()?.text()?;
       let tauri_html = TauriHtml::new(&config.build.dist_dir, response)
         .global_tauri(config.build.with_global_tauri)

+ 17 - 16
cli/core/src/helpers/config.rs

@@ -1,5 +1,5 @@
 use json_patch::merge;
-use once_cell::sync::OnceCell;
+use once_cell::sync::Lazy;
 use serde::de::{Deserializer, Error as DeError, Visitor};
 use serde::ser::Serializer;
 use serde::{Deserialize, Serialize};
@@ -8,8 +8,14 @@ use serde_json::Value as JsonValue;
 use std::collections::HashMap;
 use std::fs::File;
 use std::io::BufReader;
+use std::sync::{Arc, Mutex};
 
-static CONFIG: OnceCell<Config> = OnceCell::new();
+pub type ConfigHandle = Arc<Mutex<Option<Config>>>;
+
+fn config_handle() -> &'static ConfigHandle {
+  static CONFING_HANDLE: Lazy<ConfigHandle> = Lazy::new(Default::default);
+  &CONFING_HANDLE
+}
 
 /// The window configuration object.
 #[derive(PartialEq, Clone, Deserialize, Serialize, Debug)]
@@ -390,11 +396,9 @@ fn default_build() -> BuildConfig {
 }
 
 /// Gets the static parsed config from `tauri.conf.json`.
-fn get_internal(merge_config: Option<&str>, reload: bool) -> crate::Result<&'static Config> {
-  if let Some(config) = CONFIG.get() {
-    if !reload {
-      return Ok(config);
-    }
+fn get_internal(merge_config: Option<&str>, reload: bool) -> crate::Result<ConfigHandle> {
+  if !reload && config_handle().lock().unwrap().is_some() {
+    return Ok(config_handle().clone());
   }
 
   let path = super::app_paths::tauri_dir().join("tauri.conf.json");
@@ -408,19 +412,16 @@ fn get_internal(merge_config: Option<&str>, reload: bool) -> crate::Result<&'sta
   }
 
   let config = serde_json::from_value(config)?;
+  *config_handle().lock().unwrap() = Some(config);
 
-  CONFIG
-    .set(config)
-    .map_err(|_| anyhow::anyhow!("failed to set CONFIG"))?;
-
-  let config = CONFIG.get().unwrap();
-  Ok(config)
+  Ok(config_handle().clone())
 }
 
-pub fn get(merge_config: Option<&str>) -> crate::Result<&'static Config> {
+pub fn get(merge_config: Option<&str>) -> crate::Result<ConfigHandle> {
   get_internal(merge_config, false)
 }
 
-pub fn reload(merge_config: Option<&str>) -> crate::Result<&'static Config> {
-  get_internal(merge_config, true)
+pub fn reload(merge_config: Option<&str>) -> crate::Result<()> {
+  get_internal(merge_config, true)?;
+  Ok(())
 }

+ 6 - 2
cli/core/src/helpers/manifest.rs

@@ -1,4 +1,4 @@
-use super::{app_paths::tauri_dir, config::Config};
+use super::{app_paths::tauri_dir, config::ConfigHandle};
 
 use convert_case::{Case, Casing};
 use toml_edit::{Array, Document, Value};
@@ -6,7 +6,7 @@ use toml_edit::{Array, Document, Value};
 use std::fs::File;
 use std::io::{Read, Write};
 
-pub fn rewrite_manifest(config: &Config) -> crate::Result<()> {
+pub fn rewrite_manifest(config: ConfigHandle) -> crate::Result<()> {
   let manifest_path = tauri_dir().join("Cargo.toml");
   let mut manifest_str = String::new();
   let mut manifest_file = File::open(&manifest_path)?;
@@ -20,6 +20,10 @@ pub fn rewrite_manifest(config: &Config) -> crate::Result<()> {
 
   let entry = dependencies.entry("tauri");
   let tauri = entry.as_value_mut();
+
+  let config_guard = config.lock().unwrap();
+  let config = config_guard.as_ref().unwrap();
+
   if let Some(tauri) = tauri {
     let mut features: Array = Default::default();
 

+ 1 - 5
tauri/examples/communication/dist/index.tauri.html

@@ -142,11 +142,7 @@ if (!String.prototype.startsWith) {
     function (e) {
       var target = e.target
       while (target != null) {
-        if (
-          target.matches
-            ? target.matches('img')
-            : target.msMatchesSelector('img')
-        ) {
+        if (target.matches('img')) {
           window.__TAURI__.loadAsset(target.src, 'image').then(function (img) {
             target.src = img
           })

+ 2 - 2
tauri/examples/communication/src-tauri/Cargo.lock

@@ -1509,9 +1509,9 @@ dependencies = [
 
 [[package]]
 name = "tiny_http"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15ce4fc3c4cdea1a4399bb1819a539195fb69db4bbe0bde5b7c7f18fed412e02"
+checksum = "eded47106b8e52d8ed8119f0ea6e8c0f5881e69783e0297b5a8462958f334bc1"
 dependencies = [
  "ascii",
  "chrono",