From b15b859cf636ba08abd44dcfb3d4b08e2e7fa0a4 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Thu, 14 May 2026 12:33:17 +0800 Subject: [PATCH 01/15] refactor: make error dialog take `&'static str` (#15369) * refactor: make error dialog take `&'static str` * Add comments --- crates/tauri-runtime-wry/src/dialog/mod.rs | 4 +++- crates/tauri-runtime-wry/src/dialog/windows.rs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/crates/tauri-runtime-wry/src/dialog/mod.rs b/crates/tauri-runtime-wry/src/dialog/mod.rs index 156d6a6d2a4c..3befa7b8a0bf 100644 --- a/crates/tauri-runtime-wry/src/dialog/mod.rs +++ b/crates/tauri-runtime-wry/src/dialog/mod.rs @@ -5,7 +5,9 @@ #[cfg(windows)] mod windows; -pub fn error>(err: S) { +// Takes a `&'static str` here since we convert clickable hyperlinks, +// DO NOT pass in untrusted input +pub fn error(err: &'static str) { #[cfg(windows)] windows::error(err); diff --git a/crates/tauri-runtime-wry/src/dialog/windows.rs b/crates/tauri-runtime-wry/src/dialog/windows.rs index 2f520c563723..0f9b2c2a65e1 100644 --- a/crates/tauri-runtime-wry/src/dialog/windows.rs +++ b/crates/tauri-runtime-wry/src/dialog/windows.rs @@ -12,8 +12,8 @@ enum Level { Info, } -pub fn error>(err: S) { - dialog_inner(err.as_ref(), Level::Error); +pub fn error(err: &'static str) { + dialog_inner(err, Level::Error); } fn dialog_inner(err: &str, level: Level) { From 32d81661eedb7524b36f4c422606fa1e93ac917b Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Thu, 14 May 2026 18:20:22 +0300 Subject: [PATCH 02/15] feat: add Windows VC runtime linking and bundling options (#15372) --- .changes/bundle-vc-runtime.md | 7 + .changes/static-vc-runtime.md | 6 + .changes/tauri-build-static-vc-runtime.md | 5 + crates/tauri-build/src/lib.rs | 112 +++++++++++- crates/tauri-bundler/Cargo.toml | 4 +- crates/tauri-bundler/src/bundle.rs | 2 + crates/tauri-bundler/src/bundle/settings.rs | 8 + .../tauri-bundler/src/bundle/windows/mod.rs | 2 +- .../src/bundle/windows/msi/mod.rs | 17 +- .../src/bundle/windows/nsis/mod.rs | 18 +- .../tauri-bundler/src/bundle/windows/util.rs | 169 +++++++++++++++++- .../src/bundle/windows}/vswhere.exe | Bin crates/tauri-bundler/src/error.rs | 4 +- crates/tauri-cli/ENVIRONMENT_VARIABLES.md | 2 + crates/tauri-cli/config.schema.json | 35 +++- crates/tauri-cli/src/info/env_system.rs | 14 +- crates/tauri-cli/src/interface/rust.rs | 1 + .../tauri-cli/src/interface/rust/desktop.rs | 4 - .../schemas/config.schema.json | 35 +++- crates/tauri-utils/src/config.rs | 57 +++++- 20 files changed, 474 insertions(+), 28 deletions(-) create mode 100644 .changes/bundle-vc-runtime.md create mode 100644 .changes/static-vc-runtime.md create mode 100644 .changes/tauri-build-static-vc-runtime.md rename crates/{tauri-cli/scripts => tauri-bundler/src/bundle/windows}/vswhere.exe (100%) diff --git a/.changes/bundle-vc-runtime.md b/.changes/bundle-vc-runtime.md new file mode 100644 index 000000000000..15d7fa313c29 --- /dev/null +++ b/.changes/bundle-vc-runtime.md @@ -0,0 +1,7 @@ +--- +"tauri-bundler": "minor:feat" +"tauri-cli": "minor:feat" +"tauri-utils": "minor:feat" +--- + +Added `bundle.windows.bundleVCRuntime` to copy the Visual C++ runtime DLLs into Windows MSI and NSIS installers. The bundler locates the runtime through `VCTOOLS_REDIST_DIR` or the bundled `vswhere.exe`. diff --git a/.changes/static-vc-runtime.md b/.changes/static-vc-runtime.md new file mode 100644 index 000000000000..22f770e27167 --- /dev/null +++ b/.changes/static-vc-runtime.md @@ -0,0 +1,6 @@ +--- +"tauri-cli": "minor:feat" +"tauri-utils": "minor:feat" +--- + +Added `build.windows.staticVCRuntime` to control MSVC static runtime linking. The `STATIC_VCRUNTIME` environment variable is now deprecated and emits a migration warning when used. diff --git a/.changes/tauri-build-static-vc-runtime.md b/.changes/tauri-build-static-vc-runtime.md new file mode 100644 index 000000000000..98f0d0517137 --- /dev/null +++ b/.changes/tauri-build-static-vc-runtime.md @@ -0,0 +1,5 @@ +--- +"tauri-build": "minor:feat" +--- + +Added `tauri_build::WindowsAttributes::static_vc_runtime` to control MSVC static runtime linking from build scripts. diff --git a/crates/tauri-build/src/lib.rs b/crates/tauri-build/src/lib.rs index 6c171a3005f9..db62722ef275 100644 --- a/crates/tauri-build/src/lib.rs +++ b/crates/tauri-build/src/lib.rs @@ -215,6 +215,8 @@ fn cfg_alias(alias: &str, has_feature: bool) { #[derive(Debug)] pub struct WindowsAttributes { window_icon_path: Option, + /// Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets + static_vc_runtime: Option, /// A string containing an [application manifest] to be included with the application on Windows. /// /// Defaults to: @@ -257,6 +259,7 @@ impl WindowsAttributes { pub fn new() -> Self { Self { window_icon_path: Default::default(), + static_vc_runtime: None, app_manifest: Some(include_str!("windows-app-manifest.xml").into()), append_rc_content: Vec::new(), } @@ -268,6 +271,7 @@ impl WindowsAttributes { Self { app_manifest: None, window_icon_path: Default::default(), + static_vc_runtime: None, append_rc_content: Vec::new(), } } @@ -282,6 +286,15 @@ impl WindowsAttributes { self } + /// Sets whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets. + /// + /// If unset, this is read from `build > windows > staticVCRuntime` in the Tauri configuration. + #[must_use] + pub fn static_vc_runtime(mut self, static_vc_runtime: bool) -> Self { + self.static_vc_runtime.replace(static_vc_runtime); + self + } + /// Sets the [application manifest] to be included with the application on Windows. /// /// Defaults to: @@ -489,6 +502,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> { json_patch::merge(&mut config, &merge_config); } let config: Config = serde_json::from_value(config)?; + let static_vc_runtime = should_static_link_vc_runtime(&config, &attributes); let s = config.identifier.split('.'); let last = s.clone().count() - 1; @@ -705,7 +719,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> { } } } - "msvc" if env::var_os("STATIC_VCRUNTIME").is_some_and(|v| v == "true") => { + "msvc" if static_vc_runtime => { static_vcruntime::build(); } _ => (), @@ -726,6 +740,20 @@ fn to_winres_version(v: &semver::Version) -> u64 { (v.major << 48) | (v.minor << 32) | (v.patch << 16) | build } +fn should_static_link_vc_runtime(config: &Config, attributes: &Attributes) -> bool { + if let Some(value) = env::var_os("STATIC_VCRUNTIME") { + println!( + "cargo:warning=STATIC_VCRUNTIME is deprecated; use build.windows.staticVCRuntime in tauri.conf.json or tauri_build::WindowsAttributes::static_vc_runtime instead." + ); + value != "false" + } else { + attributes + .windows_attributes + .static_vc_runtime + .unwrap_or(config.build.windows.static_vc_runtime) + } +} + #[cfg(test)] mod tests { use semver::Version; @@ -769,4 +797,86 @@ mod tests { (1 << 48) | (2 << 32) | (3 << 16) ); } + + #[test] + fn static_vc_runtime_chain() { + // 1. Nothing is set, should default to true + let config = tauri_utils::config::Config::default(); + let attributes = crate::Attributes::new(); + assert!(crate::should_static_link_vc_runtime(&config, &attributes)); + + // 2. Set to anything but "false" in env, should be true + std::env::set_var("STATIC_VCRUNTIME", "qweqe"); + let config = tauri_utils::config::Config::default(); + let attributes = crate::Attributes::new(); + assert!(crate::should_static_link_vc_runtime(&config, &attributes)); + std::env::remove_var("STATIC_VCRUNTIME"); + + // 3. Set to "false" in env, should be false + std::env::set_var("STATIC_VCRUNTIME", "false"); + let config = tauri_utils::config::Config::default(); + let attributes = crate::Attributes::new(); + assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); + std::env::remove_var("STATIC_VCRUNTIME"); + + // 4. Set to true in attributes, should be true + let config = tauri_utils::config::Config::default(); + let attributes = crate::Attributes::new() + .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(true)); + assert!(crate::should_static_link_vc_runtime(&config, &attributes)); + + // 5. Set to false in attributes, should be false + let config = tauri_utils::config::Config::default(); + let attributes = crate::Attributes::new() + .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(false)); + assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); + + // 6. Set to true in config, should be true + let config = tauri_utils::config::Config { + build: tauri_utils::config::BuildConfig { + windows: tauri_utils::config::WindowsBuildConfig { + static_vc_runtime: true, + }, + ..Default::default() + }, + ..Default::default() + }; + let attributes = crate::Attributes::new(); + assert!(crate::should_static_link_vc_runtime(&config, &attributes)); + + // 7. Set to false in config, should be false + let config = tauri_utils::config::Config { + build: tauri_utils::config::BuildConfig { + windows: tauri_utils::config::WindowsBuildConfig { + static_vc_runtime: false, + }, + ..Default::default() + }, + ..Default::default() + }; + let attributes = crate::Attributes::new(); + assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); + + // 8. Set to true in config and false in attributes, should be false because attributes takes precedence over config + let config = tauri_utils::config::Config { + build: tauri_utils::config::BuildConfig { + windows: tauri_utils::config::WindowsBuildConfig { + static_vc_runtime: true, + }, + ..Default::default() + }, + ..Default::default() + }; + let attributes = crate::Attributes::new() + .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(false)); + assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); + + // 9. Set to false in env and true in attributes, should be false because env takes precedence over attributes + std::env::set_var("STATIC_VCRUNTIME", "false"); + let config = tauri_utils::config::Config::default(); + let attributes = crate::Attributes::new() + .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(true)); + assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); + std::env::remove_var("STATIC_VCRUNTIME"); + } } diff --git a/crates/tauri-bundler/Cargo.toml b/crates/tauri-bundler/Cargo.toml index 5dc1cdb117b3..ba4b38a684e9 100644 --- a/crates/tauri-bundler/Cargo.toml +++ b/crates/tauri-bundler/Cargo.toml @@ -50,7 +50,6 @@ plist = "1" [target."cfg(target_os = \"windows\")".dependencies] bitness = "0.4" windows-registry = "0.5" -glob = "0.3" [target."cfg(target_os = \"windows\")".dependencies.windows-sys] version = "0.60" @@ -67,6 +66,9 @@ ar = "0.9" md5 = "0.8" rpm = { version = "0.16", features = ["bzip2-compression"] } +[target."cfg(any(target_os = \"windows\", target_os = \"macos\", target_os = \"linux\"))".dependencies] +glob = "0.3" + [target."cfg(unix)".dependencies] which = "8" diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index ab0a45032f93..bda981e6fc4f 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -14,6 +14,8 @@ mod settings; mod updater_bundle; mod windows; +pub use windows::vswhere_path; + use tauri_utils::{display_path, platform::Target as TargetPlatform}; const BUNDLE_VAR_TOKEN: &[u8] = b"__TAURI_BUNDLE_TYPE_VAR_UNK"; diff --git a/crates/tauri-bundler/src/bundle/settings.rs b/crates/tauri-bundler/src/bundle/settings.rs index 7580a0adbc95..62e6557863a1 100644 --- a/crates/tauri-bundler/src/bundle/settings.rs +++ b/crates/tauri-bundler/src/bundle/settings.rs @@ -603,6 +603,13 @@ pub struct WindowsSettings { /// if the user's WebView2 is older than this version, /// the installer will try to trigger a WebView2 update. pub minimum_webview2_version: Option, + /// Whether to bundle the Visual C++ runtime DLLs alongside the application. + /// + /// This can be particularly useful when the application includes sidecars or DLLs that do not + /// statically link the Visual C++ runtime and require the runtime DLLs at runtime, and users + /// should not be required to install the Visual C++ Redistributable. This can also be useful + /// when `static_vc_runtime` is set to `false`. + pub bundle_vc_runtime: bool, } impl WindowsSettings { @@ -629,6 +636,7 @@ mod _default { allow_downgrades: true, sign_command: None, minimum_webview2_version: None, + bundle_vc_runtime: false, } } } diff --git a/crates/tauri-bundler/src/bundle/windows/mod.rs b/crates/tauri-bundler/src/bundle/windows/mod.rs index b92fb5f56216..2d59a28f7d00 100644 --- a/crates/tauri-bundler/src/bundle/windows/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/mod.rs @@ -11,6 +11,6 @@ pub mod sign; mod util; pub use util::{ - NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME, + vswhere_path, NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME, WIX_UPDATER_OUTPUT_FOLDER_NAME, }; diff --git a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs index ad0533601686..2b7452291f40 100644 --- a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs @@ -9,7 +9,7 @@ use crate::{ windows::{ sign::{should_sign, try_sign}, util::{ - download_webview2_bootstrapper, download_webview2_offline_installer, + download_webview2_bootstrapper, download_webview2_offline_installer, vc_runtime_dlls, WIX_OUTPUT_FOLDER_NAME, WIX_UPDATER_OUTPUT_FOLDER_NAME, }, }, @@ -1066,6 +1066,21 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { let mut dlls = Vec::new(); + if settings.windows().bundle_vc_runtime { + for dll in vc_runtime_dlls(settings.binary_arch())? { + let resource_path = dunce::simplified(&dll); + if added_resources.contains(&resource_path.to_path_buf()) { + continue; + } + added_resources.push(resource_path.to_path_buf()); + dlls.push(ResourceFile { + id: format!("I{}", Uuid::new_v4().as_simple()), + guid: Uuid::new_v4().to_string(), + path: resource_path.to_path_buf(), + }); + } + } + // TODO: The bundler should not include all DLLs it finds. Instead it should only include WebView2Loader.dll if present and leave the rest to the resources config. let out_dir = settings.project_out_directory(); for dll in glob::glob( diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs index 0ad87c188cab..b78334426c6a 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -8,7 +8,7 @@ use crate::{ windows::{ sign::{should_sign, sign_command, try_sign}, util::{ - download_webview2_bootstrapper, download_webview2_offline_installer, + download_webview2_bootstrapper, download_webview2_offline_installer, vc_runtime_dlls, NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, }, }, @@ -774,6 +774,22 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { } } + if settings.windows().bundle_vc_runtime { + for dll in vc_runtime_dlls(settings.binary_arch())? { + let dll = dunce::simplified(&dll).to_path_buf(); + if added_resources.contains(&dll) { + continue; + } + let target = PathBuf::from( + dll + .file_name() + .expect("failed to extract Visual C++ runtime DLL filename"), + ); + added_resources.push(dll.clone()); + resources.insert(dll, (PathBuf::new(), target)); + } + } + for resource in settings.resource_files().iter() { let resource = resource?; diff --git a/crates/tauri-bundler/src/bundle/windows/util.rs b/crates/tauri-bundler/src/bundle/windows/util.rs index e716ad7bbef5..4e606f04e090 100644 --- a/crates/tauri-bundler/src/bundle/windows/util.rs +++ b/crates/tauri-bundler/src/bundle/windows/util.rs @@ -2,12 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +#[cfg(windows)] +use std::process::Command; use std::{ - fs::create_dir_all, + fs, + io::Write, path::{Path, PathBuf}, }; use ureq::ResponseExt; +use crate::bundle::settings::Arch; use crate::utils::http_utils::{base_ureq_agent, download}; pub const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703"; @@ -22,6 +26,11 @@ pub const NSIS_UPDATER_OUTPUT_FOLDER_NAME: &str = "nsis-updater"; pub const WIX_OUTPUT_FOLDER_NAME: &str = "msi"; pub const WIX_UPDATER_OUTPUT_FOLDER_NAME: &str = "msi-updater"; +const VSWHERE: &[u8] = include_bytes!("vswhere.exe"); +const VCTOOLS_REDIST_DIR_ENV_VAR: &str = "VCTOOLS_REDIST_DIR"; +#[cfg(windows)] +const VC_REDIST_COMPONENT: &str = "Microsoft.VisualStudio.Component.VC.Redist.14.Latest"; + pub fn webview2_guid_path(url: &str) -> crate::Result<(String, String)> { let agent = base_ureq_agent(); let response = agent.head(url).call().map_err(Box::new)?; @@ -57,12 +66,168 @@ pub fn download_webview2_offline_installer(base_path: &Path, arch: &str) -> crat let dir_path = base_path.join(guid); let file_path = dir_path.join(filename); if !file_path.exists() { - create_dir_all(dir_path)?; + fs::create_dir_all(dir_path)?; std::fs::write(&file_path, download(url)?)?; } Ok(file_path) } +/// Finds the Visual C++ runtime DLLs for the given architecture. +pub fn vc_runtime_dlls(arch: Arch) -> crate::Result> { + let arch = vc_runtime_arch(arch)?; + let redist_dir = vc_redist_dir()?; + let runtime_dir = vc_runtime_dir(&redist_dir, arch)?; + + let dlls = glob::glob(&glob_path(&runtime_dir, "*.dll"))?.collect::, _>>()?; + if dlls.is_empty() { + return Err(crate::Error::GenericError(format!( + "no Visual C++ runtime DLLs found in `{}`", + runtime_dir.display() + ))); + } + + Ok(dlls) +} + +#[inline(always)] +fn vc_runtime_arch(arch: Arch) -> crate::Result<&'static str> { + match arch { + Arch::X86_64 => Ok("x64"), + Arch::X86 => Ok("x86"), + Arch::AArch64 => Ok("arm64"), + _ => Err(crate::Error::GenericError( + "bundling the Visual C++ runtime is only supported for Windows x86, x64 and arm64 targets" + .into(), + )), + } +} + +#[cfg(windows)] +fn visual_studio_dir() -> crate::Result { + let Some(vswhere) = vswhere_path() else { + return Err(crate::Error::GenericError( + "failed to prepare bundled vswhere.exe".into(), + )); + }; + + let output = Command::new(vswhere) + .args([ + "-latest", + "-prerelease", + "-products", + "*", + "-requires", + VC_REDIST_COMPONENT, + "-property", + "installationPath", + "-format", + "value", + "-utf8", + ]) + .output()?; + + if !output.status.success() { + return Err(crate::Error::GenericError(format!( + "failed to locate Visual Studio with the {VC_REDIST_COMPONENT} component" + ))); + } + + let stdout = String::from_utf8_lossy(&output.stdout); + let Some(vs_dir) = stdout.lines().map(str::trim).find(|line| !line.is_empty()) else { + return Err(crate::Error::GenericError(format!( + "failed to locate Visual Studio with the {VC_REDIST_COMPONENT} component" + ))); + }; + + Ok(PathBuf::from(vs_dir)) +} + +fn vc_redist_dir() -> crate::Result { + if let Ok(redist_dir) = std::env::var(VCTOOLS_REDIST_DIR_ENV_VAR) { + return Ok(PathBuf::from(redist_dir)); + } + + #[cfg(windows)] + { + let vs_dir = visual_studio_dir()?; + Ok(vs_dir.join("VC/Redist/MSVC")) + } + + #[cfg(not(windows))] + { + Err(crate::Error::GenericError(format!( + "failed to find Visual C++ runtime redist directory; set {VCTOOLS_REDIST_DIR_ENV_VAR} when bundling the Visual C++ runtime from non-Windows hosts" + ))) + } +} + +fn vc_runtime_dir(redist_dir: &Path, arch: &str) -> crate::Result { + let Some(latest_version_dir) = latest_vc_redist_version_dir(redist_dir)? else { + return Err(crate::Error::GenericError(format!( + "failed to find Visual C++ runtime versions in `{}`", + redist_dir.display() + ))); + }; + + let arch_dir = latest_version_dir.join(arch); + let Some(runtime_dir) = glob::glob(&glob_path(&arch_dir, "Microsoft.VC*.CRT"))? + .filter_map(Result::ok) + .find(|path| path.is_dir()) + else { + return Err(crate::Error::GenericError(format!( + "failed to find Visual C++ runtime directory for `{arch}` in `{}`", + arch_dir.display() + ))); + }; + + Ok(runtime_dir) +} + +fn latest_vc_redist_version_dir(redist_dir: &Path) -> crate::Result> { + let dir = fs::read_dir(redist_dir)? + .flatten() + .map(|entry| entry.path()) + .filter(|path| path.is_dir()) + .filter_map(|path| { + let version = path + .file_name()? + .to_str()? + .parse::() + .ok()?; + Some((version, path)) + }) + .max_by(|(a, _), (b, _)| a.cmp(b)) + .map(|(_, path)| path); + Ok(dir) +} + +/// Builds a glob pattern from a literal base path and an unescaped glob suffix. +/// +/// The base path is escaped so Visual Studio paths containing glob metacharacters are treated as +/// literal directories, while `pattern` remains active glob syntax. +fn glob_path(path: &Path, pattern: &str) -> String { + PathBuf::from(glob::Pattern::escape(&path.to_string_lossy())) + .join(pattern) + .to_string_lossy() + .into_owned() +} + +/// Returns the bundled `vswhere.exe` path. +/// +/// The executable is written to a temporary file so callers do not depend on a system-installed +/// `vswhere.exe`. +pub fn vswhere_path() -> Option { + let mut vswhere = std::env::temp_dir(); + vswhere.push("vswhere.exe"); + + if !vswhere.exists() { + let mut file = std::fs::File::create(&vswhere).ok()?; + file.write_all(VSWHERE).ok()?; + } + + Some(vswhere) +} + #[cfg(target_os = "windows")] pub fn processor_architecture<'a>() -> Option<&'a str> { use windows_sys::Win32::System::SystemInformation::{ diff --git a/crates/tauri-cli/scripts/vswhere.exe b/crates/tauri-bundler/src/bundle/windows/vswhere.exe similarity index 100% rename from crates/tauri-cli/scripts/vswhere.exe rename to crates/tauri-bundler/src/bundle/windows/vswhere.exe diff --git a/crates/tauri-bundler/src/error.rs b/crates/tauri-bundler/src/error.rs index 40547a3eea39..211b5148dcd9 100644 --- a/crates/tauri-bundler/src/error.rs +++ b/crates/tauri-bundler/src/error.rs @@ -79,11 +79,11 @@ pub enum Error { #[error("`{0}`")] HttpError(#[from] Box), /// Invalid glob pattern. - #[cfg(windows)] + #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] #[error("{0}")] GlobPattern(#[from] glob::PatternError), /// Failed to use glob pattern. - #[cfg(windows)] + #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] #[error("`{0}`")] Glob(#[from] glob::GlobError), /// Failed to parse the URL diff --git a/crates/tauri-cli/ENVIRONMENT_VARIABLES.md b/crates/tauri-cli/ENVIRONMENT_VARIABLES.md index 5a8a18100a18..f6f400ff7678 100644 --- a/crates/tauri-cli/ENVIRONMENT_VARIABLES.md +++ b/crates/tauri-cli/ENVIRONMENT_VARIABLES.md @@ -24,6 +24,8 @@ These environment variables are inputs to the CLI which may have an equivalent C - `TAURI_SIGNING_RPM_KEY` — The private GPG key used to sign the RPM bundle, exported to its ASCII-armored format. - `TAURI_SIGNING_RPM_KEY_PASSPHRASE` — The GPG key passphrase for `TAURI_SIGNING_RPM_KEY`, if needed. - `TAURI_WINDOWS_SIGNTOOL_PATH` — Specify a path to `signtool.exe` used for code signing the application on Windows. +- `STATIC_VCRUNTIME` — Deprecated. Set `build > windows > staticVCRuntime` in `tauri.conf.json` instead. +- `VCTOOLS_REDIST_DIR` — Override the Visual C++ redistributable root directory used when `bundle > windows > bundleVCRuntime` is enabled. If unset, Tauri uses its bundled `vswhere.exe` to locate Visual Studio and derive this directory. - `APPLE_CERTIFICATE` — Base64 encoded of the `.p12` certificate for code signing. To get this value, run `openssl base64 -in MyCertificate.p12 -out MyCertificate-base64.txt`. - `APPLE_CERTIFICATE_PASSWORD` — The password you used to export the certificate. - `APPLE_ID` — The Apple ID used to notarize the application. If this environment variable is provided, `APPLE_PASSWORD` and `APPLE_TEAM_ID` must also be set. Alternatively, `APPLE_API_KEY` and `APPLE_API_ISSUER` can be used to authenticate. diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index dbbd5dff137e..64a7109d95cc 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -71,7 +71,10 @@ "description": "The build configuration.", "default": { "additionalWatchFolders": [], - "removeUnusedCommands": false + "removeUnusedCommands": false, + "windows": { + "staticVCRuntime": true + } }, "allOf": [ { @@ -129,6 +132,7 @@ "useLocalToolsDir": false, "windows": { "allowDowngrades": true, + "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -1971,6 +1975,17 @@ "items": { "type": "string" } + }, + "windows": { + "description": "Windows-specific build configuration.", + "default": { + "staticVCRuntime": true + }, + "allOf": [ + { + "$ref": "#/definitions/WindowsBuildConfig" + } + ] } }, "additionalProperties": false @@ -2098,6 +2113,18 @@ } ] }, + "WindowsBuildConfig": { + "description": "Windows-specific build configuration.", + "type": "object", + "properties": { + "staticVCRuntime": { + "description": "Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, "BundleConfig": { "description": "Configuration for tauri-bundler.\n\n See more: ", "type": "object", @@ -2229,6 +2256,7 @@ "description": "Configuration for the Windows bundles.", "default": { "allowDowngrades": true, + "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -2749,6 +2777,11 @@ "type": "null" } ] + }, + "bundleVCRuntime": { + "description": "Whether to bundle the Visual C++ runtime DLLs alongside the application.\n\n This can be particularly useful when your application includes sidecars or DLLs that do\n not statically link the Visual C++ runtime and require the runtime DLLs at runtime, and\n you do not want to require users to install the Visual C++ Redistributable. This can also\n be useful when `build > windows > staticVCRuntime` is set to `false`.", + "default": false, + "type": "boolean" } }, "additionalProperties": false diff --git a/crates/tauri-cli/src/info/env_system.rs b/crates/tauri-cli/src/info/env_system.rs index 0087319eb820..fb429c0db8f5 100644 --- a/crates/tauri-cli/src/info/env_system.rs +++ b/crates/tauri-cli/src/info/env_system.rs @@ -17,20 +17,10 @@ struct VsInstanceInfo { display_name: String, } -#[cfg(windows)] -const VSWHERE: &[u8] = include_bytes!("../../scripts/vswhere.exe"); - #[cfg(windows)] fn build_tools_version() -> crate::Result> { - let mut vswhere = std::env::temp_dir(); - vswhere.push("vswhere.exe"); - - if !vswhere.exists() { - if let Ok(mut file) = std::fs::File::create(&vswhere) { - use std::io::Write; - let _ = file.write_all(VSWHERE); - } - } + let vswhere = + tauri_bundler::bundle::vswhere_path().context("failed to find or prepare vswhere.exe")?; // Check if there are Visual Studio installations that have the "MSVC - C++ Buildtools" and "Windows SDK" components. // Both the Windows 10 and Windows 11 SDKs work so we need to query it twice. diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index e18e8308f444..0b76a19ba0d7 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -1658,6 +1658,7 @@ fn tauri_config_to_bundle_settings( allow_downgrades: config.windows.allow_downgrades, sign_command: config.windows.sign_command.map(custom_sign_settings), minimum_webview2_version: config.windows.minimum_webview2_version, + bundle_vc_runtime: config.windows.bundle_vc_runtime, }, license: config.license.or_else(|| { settings diff --git a/crates/tauri-cli/src/interface/rust/desktop.rs b/crates/tauri-cli/src/interface/rust/desktop.rs index ddde0a4f0a44..ed252fb10c83 100644 --- a/crates/tauri-cli/src/interface/rust/desktop.rs +++ b/crates/tauri-cli/src/interface/rust/desktop.rs @@ -159,10 +159,6 @@ pub fn build( let out_dir = app_settings.out_dir(&options, tauri_dir)?; let bin_path = app_settings.app_binary_path(&options, tauri_dir)?; - if !std::env::var_os("STATIC_VCRUNTIME").is_some_and(|v| v == "false") { - std::env::set_var("STATIC_VCRUNTIME", "true"); - } - if options.target == Some("universal-apple-darwin".into()) { std::fs::create_dir_all(&out_dir) .fs_context("failed to create project out directory", out_dir.clone())?; diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index dbbd5dff137e..64a7109d95cc 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -71,7 +71,10 @@ "description": "The build configuration.", "default": { "additionalWatchFolders": [], - "removeUnusedCommands": false + "removeUnusedCommands": false, + "windows": { + "staticVCRuntime": true + } }, "allOf": [ { @@ -129,6 +132,7 @@ "useLocalToolsDir": false, "windows": { "allowDowngrades": true, + "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -1971,6 +1975,17 @@ "items": { "type": "string" } + }, + "windows": { + "description": "Windows-specific build configuration.", + "default": { + "staticVCRuntime": true + }, + "allOf": [ + { + "$ref": "#/definitions/WindowsBuildConfig" + } + ] } }, "additionalProperties": false @@ -2098,6 +2113,18 @@ } ] }, + "WindowsBuildConfig": { + "description": "Windows-specific build configuration.", + "type": "object", + "properties": { + "staticVCRuntime": { + "description": "Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, "BundleConfig": { "description": "Configuration for tauri-bundler.\n\n See more: ", "type": "object", @@ -2229,6 +2256,7 @@ "description": "Configuration for the Windows bundles.", "default": { "allowDowngrades": true, + "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -2749,6 +2777,11 @@ "type": "null" } ] + }, + "bundleVCRuntime": { + "description": "Whether to bundle the Visual C++ runtime DLLs alongside the application.\n\n This can be particularly useful when your application includes sidecars or DLLs that do\n not statically link the Visual C++ runtime and require the runtime DLLs at runtime, and\n you do not want to require users to install the Visual C++ Redistributable. This can also\n be useful when `build > windows > staticVCRuntime` is set to `false`.", + "default": false, + "type": "boolean" } }, "additionalProperties": false diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index a54c619e3f6f..f5483f3b96a1 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -1078,6 +1078,19 @@ pub struct WindowsConfig { /// need to use another tool like `osslsigncode`. #[serde(alias = "sign-command")] pub sign_command: Option, + /// Whether to bundle the Visual C++ runtime DLLs alongside the application. + /// + /// This can be particularly useful when your application includes sidecars or DLLs that do + /// not statically link the Visual C++ runtime and require the runtime DLLs at runtime, and + /// you do not want to require users to install the Visual C++ Redistributable. This can also + /// be useful when `build > windows > staticVCRuntime` is set to `false`. + #[serde( + default, + rename = "bundleVCRuntime", + alias = "bundle-vc-runtime", + alias = "bundleVcRuntime" + )] + pub bundle_vc_runtime: bool, } impl Default for WindowsConfig { @@ -1093,6 +1106,7 @@ impl Default for WindowsConfig { wix: None, nsis: None, sign_command: None, + bundle_vc_runtime: false, } } } @@ -3448,6 +3462,32 @@ pub struct BuildConfig { /// Additional paths to watch for changes when running `tauri dev`. #[serde(alias = "additional-watch-directories", default)] pub additional_watch_folders: Vec, + /// Windows-specific build configuration. + #[serde(default)] + pub windows: WindowsBuildConfig, +} + +/// Windows-specific build configuration. +#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct WindowsBuildConfig { + /// Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets. + #[serde( + default = "default_true", + rename = "staticVCRuntime", + alias = "static-vc-runtime", + alias = "staticVcRuntime" + )] + pub static_vc_runtime: bool, +} + +impl Default for WindowsBuildConfig { + fn default() -> Self { + Self { + static_vc_runtime: true, + } + } } #[derive(Debug, PartialEq, Eq)] @@ -4126,6 +4166,7 @@ mod build { let features = quote!(None); let remove_unused_commands = quote!(false); let additional_watch_folders = quote!(Vec::new()); + let windows = &self.windows; literal_struct!( tokens, @@ -4138,7 +4179,20 @@ mod build { before_bundle_command, features, remove_unused_commands, - additional_watch_folders + additional_watch_folders, + windows + ); + } + } + + impl ToTokens for WindowsBuildConfig { + fn to_tokens(&self, tokens: &mut TokenStream) { + let static_vc_runtime = self.static_vc_runtime; + + literal_struct!( + tokens, + ::tauri::utils::config::WindowsBuildConfig, + static_vc_runtime ); } } @@ -4482,6 +4536,7 @@ mod test { features: None, remove_unused_commands: false, additional_watch_folders: Vec::new(), + windows: WindowsBuildConfig::default(), }; // create a bundle config From eadd8f5f49446fc5cdca0dd6094aade726f09b6b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 May 2026 10:02:58 +0800 Subject: [PATCH 03/15] chore(deps-dev): bump svelte from 5.53.11 to 5.55.7 (#15382) Bumps [svelte](https://github.com/sveltejs/svelte/tree/HEAD/packages/svelte) from 5.53.11 to 5.55.7. - [Release notes](https://github.com/sveltejs/svelte/releases) - [Changelog](https://github.com/sveltejs/svelte/blob/main/packages/svelte/CHANGELOG.md) - [Commits](https://github.com/sveltejs/svelte/commits/svelte@5.55.7/packages/svelte) --- updated-dependencies: - dependency-name: svelte dependency-version: 5.55.7 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- examples/api/package.json | 2 +- pnpm-lock.yaml | 56 ++++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/examples/api/package.json b/examples/api/package.json index d51a35a93bc3..53780ea95741 100644 --- a/examples/api/package.json +++ b/examples/api/package.json @@ -17,7 +17,7 @@ "@iconify-json/ph": "^1.2.2", "@sveltejs/vite-plugin-svelte": "^7.0.0", "@unocss/extractor-svelte": "^66.6.6", - "svelte": "^5.53.11", + "svelte": "^5.55.7", "unocss": "^66.6.6", "vite": "^8.0.5" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bc5043f3f2f..c4875aff5cf5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,13 +32,13 @@ importers: version: 1.2.2 '@sveltejs/vite-plugin-svelte': specifier: ^7.0.0 - version: 7.0.0(svelte@5.53.11)(vite@8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0)) + version: 7.0.0(svelte@5.55.7(@typescript-eslint/types@8.58.2))(vite@8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0)) '@unocss/extractor-svelte': specifier: ^66.6.6 version: 66.6.6 svelte: - specifier: ^5.53.11 - version: 5.53.11 + specifier: ^5.55.7 + version: 5.55.7(@typescript-eslint/types@8.58.2) unocss: specifier: ^66.6.6 version: 66.6.6(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(vite@8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0)) @@ -1578,6 +1578,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -1895,8 +1898,8 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - devalue@5.6.4: - resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} + devalue@5.8.1: + resolution: {integrity: sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw==} duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} @@ -1973,8 +1976,13 @@ packages: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} - esrap@2.2.3: - resolution: {integrity: sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==} + esrap@2.2.8: + resolution: {integrity: sha512-MPweq2EvEGj8jwOI7Hgycw/QIHzqA1EbAM8lG7p+FBfZbZq/hQ6h3AMsqnu/djzisH1KVWNzbb7LSgIVtMlPSg==} + peerDependencies: + '@typescript-eslint/types': ^8.2.0 + peerDependenciesMeta: + '@typescript-eslint/types': + optional: true esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} @@ -2470,8 +2478,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte@5.53.11: - resolution: {integrity: sha512-GYmqRjRhJYLQBonfdfGAt28gkfWEShrtXKGXcFGneXi502aBE+I1dJcs/YQriByvP6xqXRz/OdBGC6tfvUQHyQ==} + svelte@5.55.7: + resolution: {integrity: sha512-ymI5ykLPwIHW839E053FQbI1G+jnRFJEw3Kv5Y4njixVWywQBx+NUFpkkKyk5LIb36Fg9DVXSYpqiGekLD0hyw==} engines: {node: '>=18'} terser@5.46.0: @@ -3711,7 +3719,7 @@ snapshots: '@rollup/pluginutils@5.3.0(rollup@4.60.3)': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: @@ -3802,12 +3810,12 @@ snapshots: dependencies: acorn: 8.16.0 - '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.53.11)(vite@8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0))': + '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.7(@typescript-eslint/types@8.58.2))(vite@8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.53.11 + svelte: 5.55.7(@typescript-eslint/types@8.58.2) vite: 8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0) vitefu: 1.1.2(vite@8.0.5(@emnapi/core@1.8.1)(@emnapi/runtime@1.8.1)(@types/node@24.11.0)(esbuild@0.27.3)(jiti@2.6.1)(terser@5.46.0)) @@ -3832,6 +3840,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} + '@types/json-schema@7.0.15': {} '@types/node@24.11.0': @@ -4211,7 +4221,7 @@ snapshots: detect-libc@2.1.2: {} - devalue@5.6.4: {} + devalue@5.8.1: {} duplexer@0.1.2: {} @@ -4267,7 +4277,7 @@ snapshots: eslint-scope@9.1.1: dependencies: '@types/esrecurse': 4.3.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esrecurse: 4.3.0 estraverse: 5.3.0 @@ -4324,9 +4334,11 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@2.2.3: + esrap@2.2.8(@typescript-eslint/types@8.58.2): dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + optionalDependencies: + '@typescript-eslint/types': 8.58.2 esrecurse@4.3.0: dependencies: @@ -4338,7 +4350,7 @@ snapshots: estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} @@ -4437,7 +4449,7 @@ snapshots: is-reference@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 isexe@2.0.0: {} @@ -4836,24 +4848,26 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte@5.53.11: + svelte@5.55.7(@typescript-eslint/types@8.58.2): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/trusted-types': 2.0.7 acorn: 8.16.0 aria-query: 5.3.1 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.6.4 + devalue: 5.8.1 esm-env: 1.2.2 - esrap: 2.2.3 + esrap: 2.2.8(@typescript-eslint/types@8.58.2) is-reference: 3.0.3 locate-character: 3.0.0 magic-string: 0.30.21 zimmerframe: 1.1.4 + transitivePeerDependencies: + - '@typescript-eslint/types' terser@5.46.0: dependencies: From 47e1b754951bffeedbcd6400928d60755fb954de Mon Sep 17 00:00:00 2001 From: Dominik Peters Date: Fri, 15 May 2026 18:35:56 +0200 Subject: [PATCH 04/15] fix: `set_as_windows_menu_for_nsapp` command wrongly called `set_as_help_menu_for_nsapp` (#15386) --- .changes/fix-window-menu-nsapp-command.md | 5 +++++ crates/tauri/src/menu/plugin.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 .changes/fix-window-menu-nsapp-command.md diff --git a/.changes/fix-window-menu-nsapp-command.md b/.changes/fix-window-menu-nsapp-command.md new file mode 100644 index 000000000000..22ef6a3d910b --- /dev/null +++ b/.changes/fix-window-menu-nsapp-command.md @@ -0,0 +1,5 @@ +--- +"tauri": "patch:bug" +--- + +Fixed `Submenu.setAsWindowsMenuForNSApp()` calling the Help menu setter instead of the Window menu setter. diff --git a/crates/tauri/src/menu/plugin.rs b/crates/tauri/src/menu/plugin.rs index 84ab54a98d22..7f6741d00315 100644 --- a/crates/tauri/src/menu/plugin.rs +++ b/crates/tauri/src/menu/plugin.rs @@ -815,7 +815,7 @@ fn set_as_windows_menu_for_nsapp( { let resources_table = webview.resources_table(); let submenu = resources_table.get::>(rid)?; - submenu.set_as_help_menu_for_nsapp()?; + submenu.set_as_windows_menu_for_nsapp()?; } let _ = rid; From 3fd8ba2c022717068ff6a154ce12942c3a672232 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Sat, 16 May 2026 23:00:35 +0800 Subject: [PATCH 05/15] fix: resources after empty directory not copied (#15388) * fix: resources after empty directory not copied * typo * Add empty directory test --- .changes/resources-after-empty-diretory.md | 18 ++++++++++++++++++ crates/tauri-utils/src/resources.rs | 14 +++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 .changes/resources-after-empty-diretory.md diff --git a/.changes/resources-after-empty-diretory.md b/.changes/resources-after-empty-diretory.md new file mode 100644 index 000000000000..58087ef0b68b --- /dev/null +++ b/.changes/resources-after-empty-diretory.md @@ -0,0 +1,18 @@ +--- +"tauri-utils": "patch:bug" +--- + +Fix a regression in tauri-utils 2.8.3 that made an empty directory makes it skip all the following entries, e.g. + +```json +{ + "bundle": { + "resources": [ + "empty-directory", + "README.md" + ] + } +} +``` + +if `empty-directory` is empty, the `README.md` will not be copied to the resource directory (skipped) diff --git a/crates/tauri-utils/src/resources.rs b/crates/tauri-utils/src/resources.rs index 3fd0290b78ac..c0ac56993b26 100644 --- a/crates/tauri-utils/src/resources.rs +++ b/crates/tauri-utils/src/resources.rs @@ -221,6 +221,7 @@ impl ResourcePathsIter<'_> { fn next_pattern(&mut self) -> Option> { self.current_dest = None; + self.current_iter = None; let pattern = match &mut self.pattern_iter { PatternIter::Slice(iter) => iter.next()?, @@ -237,10 +238,10 @@ impl ResourcePathsIter<'_> { Err(error) => return Some(Err(error.into())), }; match self.next_current_iter() { - Some(r) => return Some(r), + Some(r) => Some(r), None => { self.current_iter = None; - return Some(Err(crate::Error::GlobPathNotFound(pattern.clone()))); + Some(Err(crate::Error::GlobPathNotFound(pattern.clone()))) } } } else { @@ -257,12 +258,12 @@ impl ResourcePathsIter<'_> { None }, }); + // If the directory is empty, skip and continue to the next pattern + self.next_current_iter().or_else(|| self.next_pattern()) } else { - return Some(self.resource_from_path(path)); + Some(self.resource_from_path(path)) } } - - self.next_current_iter() } } @@ -358,6 +359,7 @@ mod tests { fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write(path, "").unwrap(); } + fs::create_dir_all("empty-directory").unwrap(); } fn resources_map(literal: &[(&str, &str)]) -> HashMap { @@ -377,6 +379,8 @@ mod tests { let resources = ResourcePaths::new( &[ + // `empty-directory` should not affect anything + "../empty-directory".into(), "../src/script.js".into(), "../src/assets".into(), "../src/index.html".into(), From b5b72ce51811e9f95b1f7e9a05ea19c8f12ce694 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Sat, 16 May 2026 23:19:01 +0800 Subject: [PATCH 06/15] fix(tauri-utils): preserve resource source file name when dest is empty (#15383) --- .changes/no-dest-resource-target.md | 17 +++++++++++++++++ crates/tauri-utils/src/resources.rs | 16 +++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 .changes/no-dest-resource-target.md diff --git a/.changes/no-dest-resource-target.md b/.changes/no-dest-resource-target.md new file mode 100644 index 000000000000..926b8e8c8cf3 --- /dev/null +++ b/.changes/no-dest-resource-target.md @@ -0,0 +1,17 @@ +--- +"tauri-utils": "patch:bug" +--- + +Fix a regression in tauri-utils 2.8.3 that made empty path an invalid resource target, e.g. + +```json +{ + "bundle": { + "resources": { + "README.md": "", + } + } +} +``` + +(this means `README.md` -> `$RESOURCE/README.md`, note this is a confusing behavior, and will be changed in v3) diff --git a/crates/tauri-utils/src/resources.rs b/crates/tauri-utils/src/resources.rs index c0ac56993b26..6c30b89de486 100644 --- a/crates/tauri-utils/src/resources.rs +++ b/crates/tauri-utils/src/resources.rs @@ -209,7 +209,21 @@ impl ResourcePathsIter<'_> { // preserving the file name as it is ResourcePathsInnerIter::Glob { .. } => dest.join(path.file_name().unwrap()), }, - None => dest.clone(), + None => { + if dest.components().count() == 0 { + // if current_dest is empty while processing a file pattern + // we preserve the file name as it is + // + // e.g. `{ "README.md": "" }` is `README.md` -> `$RESOURCE/README.md` + // + // TODO: This behavior is a confusing special case, + // remove this in v3 or make other cases like this work + // > `{ "README.md": "./folder/" }` is `README.md` -> `$RESOURCE/folder/README.md` (this gives `$RESOURCE/folder` today) + PathBuf::from(path.file_name().unwrap()) + } else { + dest.clone() + } + } } } else { // If [`ResourcePathsIter::pattern_iter`] is a [`PatternIter::Slice`] From 20bb033abb1947121e8158a52f46e1de36b94af7 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Sat, 16 May 2026 23:48:51 +0800 Subject: [PATCH 07/15] Revert "feat: add Windows VC runtime linking and bundling options (#15372)" (#15400) This reverts commit 32d81661eedb7524b36f4c422606fa1e93ac917b. --- .changes/bundle-vc-runtime.md | 7 - .changes/static-vc-runtime.md | 6 - .changes/tauri-build-static-vc-runtime.md | 5 - crates/tauri-build/src/lib.rs | 112 +----------- crates/tauri-bundler/Cargo.toml | 4 +- crates/tauri-bundler/src/bundle.rs | 2 - crates/tauri-bundler/src/bundle/settings.rs | 8 - .../tauri-bundler/src/bundle/windows/mod.rs | 2 +- .../src/bundle/windows/msi/mod.rs | 17 +- .../src/bundle/windows/nsis/mod.rs | 18 +- .../tauri-bundler/src/bundle/windows/util.rs | 169 +----------------- crates/tauri-bundler/src/error.rs | 4 +- crates/tauri-cli/ENVIRONMENT_VARIABLES.md | 2 - crates/tauri-cli/config.schema.json | 35 +--- .../windows => tauri-cli/scripts}/vswhere.exe | Bin crates/tauri-cli/src/info/env_system.rs | 14 +- crates/tauri-cli/src/interface/rust.rs | 1 - .../tauri-cli/src/interface/rust/desktop.rs | 4 + .../schemas/config.schema.json | 35 +--- crates/tauri-utils/src/config.rs | 57 +----- 20 files changed, 28 insertions(+), 474 deletions(-) delete mode 100644 .changes/bundle-vc-runtime.md delete mode 100644 .changes/static-vc-runtime.md delete mode 100644 .changes/tauri-build-static-vc-runtime.md rename crates/{tauri-bundler/src/bundle/windows => tauri-cli/scripts}/vswhere.exe (100%) diff --git a/.changes/bundle-vc-runtime.md b/.changes/bundle-vc-runtime.md deleted file mode 100644 index 15d7fa313c29..000000000000 --- a/.changes/bundle-vc-runtime.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri-bundler": "minor:feat" -"tauri-cli": "minor:feat" -"tauri-utils": "minor:feat" ---- - -Added `bundle.windows.bundleVCRuntime` to copy the Visual C++ runtime DLLs into Windows MSI and NSIS installers. The bundler locates the runtime through `VCTOOLS_REDIST_DIR` or the bundled `vswhere.exe`. diff --git a/.changes/static-vc-runtime.md b/.changes/static-vc-runtime.md deleted file mode 100644 index 22f770e27167..000000000000 --- a/.changes/static-vc-runtime.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-cli": "minor:feat" -"tauri-utils": "minor:feat" ---- - -Added `build.windows.staticVCRuntime` to control MSVC static runtime linking. The `STATIC_VCRUNTIME` environment variable is now deprecated and emits a migration warning when used. diff --git a/.changes/tauri-build-static-vc-runtime.md b/.changes/tauri-build-static-vc-runtime.md deleted file mode 100644 index 98f0d0517137..000000000000 --- a/.changes/tauri-build-static-vc-runtime.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": "minor:feat" ---- - -Added `tauri_build::WindowsAttributes::static_vc_runtime` to control MSVC static runtime linking from build scripts. diff --git a/crates/tauri-build/src/lib.rs b/crates/tauri-build/src/lib.rs index db62722ef275..6c171a3005f9 100644 --- a/crates/tauri-build/src/lib.rs +++ b/crates/tauri-build/src/lib.rs @@ -215,8 +215,6 @@ fn cfg_alias(alias: &str, has_feature: bool) { #[derive(Debug)] pub struct WindowsAttributes { window_icon_path: Option, - /// Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets - static_vc_runtime: Option, /// A string containing an [application manifest] to be included with the application on Windows. /// /// Defaults to: @@ -259,7 +257,6 @@ impl WindowsAttributes { pub fn new() -> Self { Self { window_icon_path: Default::default(), - static_vc_runtime: None, app_manifest: Some(include_str!("windows-app-manifest.xml").into()), append_rc_content: Vec::new(), } @@ -271,7 +268,6 @@ impl WindowsAttributes { Self { app_manifest: None, window_icon_path: Default::default(), - static_vc_runtime: None, append_rc_content: Vec::new(), } } @@ -286,15 +282,6 @@ impl WindowsAttributes { self } - /// Sets whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets. - /// - /// If unset, this is read from `build > windows > staticVCRuntime` in the Tauri configuration. - #[must_use] - pub fn static_vc_runtime(mut self, static_vc_runtime: bool) -> Self { - self.static_vc_runtime.replace(static_vc_runtime); - self - } - /// Sets the [application manifest] to be included with the application on Windows. /// /// Defaults to: @@ -502,7 +489,6 @@ pub fn try_build(attributes: Attributes) -> Result<()> { json_patch::merge(&mut config, &merge_config); } let config: Config = serde_json::from_value(config)?; - let static_vc_runtime = should_static_link_vc_runtime(&config, &attributes); let s = config.identifier.split('.'); let last = s.clone().count() - 1; @@ -719,7 +705,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> { } } } - "msvc" if static_vc_runtime => { + "msvc" if env::var_os("STATIC_VCRUNTIME").is_some_and(|v| v == "true") => { static_vcruntime::build(); } _ => (), @@ -740,20 +726,6 @@ fn to_winres_version(v: &semver::Version) -> u64 { (v.major << 48) | (v.minor << 32) | (v.patch << 16) | build } -fn should_static_link_vc_runtime(config: &Config, attributes: &Attributes) -> bool { - if let Some(value) = env::var_os("STATIC_VCRUNTIME") { - println!( - "cargo:warning=STATIC_VCRUNTIME is deprecated; use build.windows.staticVCRuntime in tauri.conf.json or tauri_build::WindowsAttributes::static_vc_runtime instead." - ); - value != "false" - } else { - attributes - .windows_attributes - .static_vc_runtime - .unwrap_or(config.build.windows.static_vc_runtime) - } -} - #[cfg(test)] mod tests { use semver::Version; @@ -797,86 +769,4 @@ mod tests { (1 << 48) | (2 << 32) | (3 << 16) ); } - - #[test] - fn static_vc_runtime_chain() { - // 1. Nothing is set, should default to true - let config = tauri_utils::config::Config::default(); - let attributes = crate::Attributes::new(); - assert!(crate::should_static_link_vc_runtime(&config, &attributes)); - - // 2. Set to anything but "false" in env, should be true - std::env::set_var("STATIC_VCRUNTIME", "qweqe"); - let config = tauri_utils::config::Config::default(); - let attributes = crate::Attributes::new(); - assert!(crate::should_static_link_vc_runtime(&config, &attributes)); - std::env::remove_var("STATIC_VCRUNTIME"); - - // 3. Set to "false" in env, should be false - std::env::set_var("STATIC_VCRUNTIME", "false"); - let config = tauri_utils::config::Config::default(); - let attributes = crate::Attributes::new(); - assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); - std::env::remove_var("STATIC_VCRUNTIME"); - - // 4. Set to true in attributes, should be true - let config = tauri_utils::config::Config::default(); - let attributes = crate::Attributes::new() - .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(true)); - assert!(crate::should_static_link_vc_runtime(&config, &attributes)); - - // 5. Set to false in attributes, should be false - let config = tauri_utils::config::Config::default(); - let attributes = crate::Attributes::new() - .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(false)); - assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); - - // 6. Set to true in config, should be true - let config = tauri_utils::config::Config { - build: tauri_utils::config::BuildConfig { - windows: tauri_utils::config::WindowsBuildConfig { - static_vc_runtime: true, - }, - ..Default::default() - }, - ..Default::default() - }; - let attributes = crate::Attributes::new(); - assert!(crate::should_static_link_vc_runtime(&config, &attributes)); - - // 7. Set to false in config, should be false - let config = tauri_utils::config::Config { - build: tauri_utils::config::BuildConfig { - windows: tauri_utils::config::WindowsBuildConfig { - static_vc_runtime: false, - }, - ..Default::default() - }, - ..Default::default() - }; - let attributes = crate::Attributes::new(); - assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); - - // 8. Set to true in config and false in attributes, should be false because attributes takes precedence over config - let config = tauri_utils::config::Config { - build: tauri_utils::config::BuildConfig { - windows: tauri_utils::config::WindowsBuildConfig { - static_vc_runtime: true, - }, - ..Default::default() - }, - ..Default::default() - }; - let attributes = crate::Attributes::new() - .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(false)); - assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); - - // 9. Set to false in env and true in attributes, should be false because env takes precedence over attributes - std::env::set_var("STATIC_VCRUNTIME", "false"); - let config = tauri_utils::config::Config::default(); - let attributes = crate::Attributes::new() - .windows_attributes(crate::WindowsAttributes::new().static_vc_runtime(true)); - assert!(!crate::should_static_link_vc_runtime(&config, &attributes)); - std::env::remove_var("STATIC_VCRUNTIME"); - } } diff --git a/crates/tauri-bundler/Cargo.toml b/crates/tauri-bundler/Cargo.toml index ba4b38a684e9..5dc1cdb117b3 100644 --- a/crates/tauri-bundler/Cargo.toml +++ b/crates/tauri-bundler/Cargo.toml @@ -50,6 +50,7 @@ plist = "1" [target."cfg(target_os = \"windows\")".dependencies] bitness = "0.4" windows-registry = "0.5" +glob = "0.3" [target."cfg(target_os = \"windows\")".dependencies.windows-sys] version = "0.60" @@ -66,9 +67,6 @@ ar = "0.9" md5 = "0.8" rpm = { version = "0.16", features = ["bzip2-compression"] } -[target."cfg(any(target_os = \"windows\", target_os = \"macos\", target_os = \"linux\"))".dependencies] -glob = "0.3" - [target."cfg(unix)".dependencies] which = "8" diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index bda981e6fc4f..ab0a45032f93 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -14,8 +14,6 @@ mod settings; mod updater_bundle; mod windows; -pub use windows::vswhere_path; - use tauri_utils::{display_path, platform::Target as TargetPlatform}; const BUNDLE_VAR_TOKEN: &[u8] = b"__TAURI_BUNDLE_TYPE_VAR_UNK"; diff --git a/crates/tauri-bundler/src/bundle/settings.rs b/crates/tauri-bundler/src/bundle/settings.rs index 62e6557863a1..7580a0adbc95 100644 --- a/crates/tauri-bundler/src/bundle/settings.rs +++ b/crates/tauri-bundler/src/bundle/settings.rs @@ -603,13 +603,6 @@ pub struct WindowsSettings { /// if the user's WebView2 is older than this version, /// the installer will try to trigger a WebView2 update. pub minimum_webview2_version: Option, - /// Whether to bundle the Visual C++ runtime DLLs alongside the application. - /// - /// This can be particularly useful when the application includes sidecars or DLLs that do not - /// statically link the Visual C++ runtime and require the runtime DLLs at runtime, and users - /// should not be required to install the Visual C++ Redistributable. This can also be useful - /// when `static_vc_runtime` is set to `false`. - pub bundle_vc_runtime: bool, } impl WindowsSettings { @@ -636,7 +629,6 @@ mod _default { allow_downgrades: true, sign_command: None, minimum_webview2_version: None, - bundle_vc_runtime: false, } } } diff --git a/crates/tauri-bundler/src/bundle/windows/mod.rs b/crates/tauri-bundler/src/bundle/windows/mod.rs index 2d59a28f7d00..b92fb5f56216 100644 --- a/crates/tauri-bundler/src/bundle/windows/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/mod.rs @@ -11,6 +11,6 @@ pub mod sign; mod util; pub use util::{ - vswhere_path, NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME, + NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, WIX_OUTPUT_FOLDER_NAME, WIX_UPDATER_OUTPUT_FOLDER_NAME, }; diff --git a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs index 2b7452291f40..ad0533601686 100644 --- a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs @@ -9,7 +9,7 @@ use crate::{ windows::{ sign::{should_sign, try_sign}, util::{ - download_webview2_bootstrapper, download_webview2_offline_installer, vc_runtime_dlls, + download_webview2_bootstrapper, download_webview2_offline_installer, WIX_OUTPUT_FOLDER_NAME, WIX_UPDATER_OUTPUT_FOLDER_NAME, }, }, @@ -1066,21 +1066,6 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { let mut dlls = Vec::new(); - if settings.windows().bundle_vc_runtime { - for dll in vc_runtime_dlls(settings.binary_arch())? { - let resource_path = dunce::simplified(&dll); - if added_resources.contains(&resource_path.to_path_buf()) { - continue; - } - added_resources.push(resource_path.to_path_buf()); - dlls.push(ResourceFile { - id: format!("I{}", Uuid::new_v4().as_simple()), - guid: Uuid::new_v4().to_string(), - path: resource_path.to_path_buf(), - }); - } - } - // TODO: The bundler should not include all DLLs it finds. Instead it should only include WebView2Loader.dll if present and leave the rest to the resources config. let out_dir = settings.project_out_directory(); for dll in glob::glob( diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs index b78334426c6a..0ad87c188cab 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -8,7 +8,7 @@ use crate::{ windows::{ sign::{should_sign, sign_command, try_sign}, util::{ - download_webview2_bootstrapper, download_webview2_offline_installer, vc_runtime_dlls, + download_webview2_bootstrapper, download_webview2_offline_installer, NSIS_OUTPUT_FOLDER_NAME, NSIS_UPDATER_OUTPUT_FOLDER_NAME, }, }, @@ -774,22 +774,6 @@ fn generate_resource_data(settings: &Settings) -> crate::Result { } } - if settings.windows().bundle_vc_runtime { - for dll in vc_runtime_dlls(settings.binary_arch())? { - let dll = dunce::simplified(&dll).to_path_buf(); - if added_resources.contains(&dll) { - continue; - } - let target = PathBuf::from( - dll - .file_name() - .expect("failed to extract Visual C++ runtime DLL filename"), - ); - added_resources.push(dll.clone()); - resources.insert(dll, (PathBuf::new(), target)); - } - } - for resource in settings.resource_files().iter() { let resource = resource?; diff --git a/crates/tauri-bundler/src/bundle/windows/util.rs b/crates/tauri-bundler/src/bundle/windows/util.rs index 4e606f04e090..e716ad7bbef5 100644 --- a/crates/tauri-bundler/src/bundle/windows/util.rs +++ b/crates/tauri-bundler/src/bundle/windows/util.rs @@ -2,16 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -#[cfg(windows)] -use std::process::Command; use std::{ - fs, - io::Write, + fs::create_dir_all, path::{Path, PathBuf}, }; use ureq::ResponseExt; -use crate::bundle::settings::Arch; use crate::utils::http_utils::{base_ureq_agent, download}; pub const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703"; @@ -26,11 +22,6 @@ pub const NSIS_UPDATER_OUTPUT_FOLDER_NAME: &str = "nsis-updater"; pub const WIX_OUTPUT_FOLDER_NAME: &str = "msi"; pub const WIX_UPDATER_OUTPUT_FOLDER_NAME: &str = "msi-updater"; -const VSWHERE: &[u8] = include_bytes!("vswhere.exe"); -const VCTOOLS_REDIST_DIR_ENV_VAR: &str = "VCTOOLS_REDIST_DIR"; -#[cfg(windows)] -const VC_REDIST_COMPONENT: &str = "Microsoft.VisualStudio.Component.VC.Redist.14.Latest"; - pub fn webview2_guid_path(url: &str) -> crate::Result<(String, String)> { let agent = base_ureq_agent(); let response = agent.head(url).call().map_err(Box::new)?; @@ -66,168 +57,12 @@ pub fn download_webview2_offline_installer(base_path: &Path, arch: &str) -> crat let dir_path = base_path.join(guid); let file_path = dir_path.join(filename); if !file_path.exists() { - fs::create_dir_all(dir_path)?; + create_dir_all(dir_path)?; std::fs::write(&file_path, download(url)?)?; } Ok(file_path) } -/// Finds the Visual C++ runtime DLLs for the given architecture. -pub fn vc_runtime_dlls(arch: Arch) -> crate::Result> { - let arch = vc_runtime_arch(arch)?; - let redist_dir = vc_redist_dir()?; - let runtime_dir = vc_runtime_dir(&redist_dir, arch)?; - - let dlls = glob::glob(&glob_path(&runtime_dir, "*.dll"))?.collect::, _>>()?; - if dlls.is_empty() { - return Err(crate::Error::GenericError(format!( - "no Visual C++ runtime DLLs found in `{}`", - runtime_dir.display() - ))); - } - - Ok(dlls) -} - -#[inline(always)] -fn vc_runtime_arch(arch: Arch) -> crate::Result<&'static str> { - match arch { - Arch::X86_64 => Ok("x64"), - Arch::X86 => Ok("x86"), - Arch::AArch64 => Ok("arm64"), - _ => Err(crate::Error::GenericError( - "bundling the Visual C++ runtime is only supported for Windows x86, x64 and arm64 targets" - .into(), - )), - } -} - -#[cfg(windows)] -fn visual_studio_dir() -> crate::Result { - let Some(vswhere) = vswhere_path() else { - return Err(crate::Error::GenericError( - "failed to prepare bundled vswhere.exe".into(), - )); - }; - - let output = Command::new(vswhere) - .args([ - "-latest", - "-prerelease", - "-products", - "*", - "-requires", - VC_REDIST_COMPONENT, - "-property", - "installationPath", - "-format", - "value", - "-utf8", - ]) - .output()?; - - if !output.status.success() { - return Err(crate::Error::GenericError(format!( - "failed to locate Visual Studio with the {VC_REDIST_COMPONENT} component" - ))); - } - - let stdout = String::from_utf8_lossy(&output.stdout); - let Some(vs_dir) = stdout.lines().map(str::trim).find(|line| !line.is_empty()) else { - return Err(crate::Error::GenericError(format!( - "failed to locate Visual Studio with the {VC_REDIST_COMPONENT} component" - ))); - }; - - Ok(PathBuf::from(vs_dir)) -} - -fn vc_redist_dir() -> crate::Result { - if let Ok(redist_dir) = std::env::var(VCTOOLS_REDIST_DIR_ENV_VAR) { - return Ok(PathBuf::from(redist_dir)); - } - - #[cfg(windows)] - { - let vs_dir = visual_studio_dir()?; - Ok(vs_dir.join("VC/Redist/MSVC")) - } - - #[cfg(not(windows))] - { - Err(crate::Error::GenericError(format!( - "failed to find Visual C++ runtime redist directory; set {VCTOOLS_REDIST_DIR_ENV_VAR} when bundling the Visual C++ runtime from non-Windows hosts" - ))) - } -} - -fn vc_runtime_dir(redist_dir: &Path, arch: &str) -> crate::Result { - let Some(latest_version_dir) = latest_vc_redist_version_dir(redist_dir)? else { - return Err(crate::Error::GenericError(format!( - "failed to find Visual C++ runtime versions in `{}`", - redist_dir.display() - ))); - }; - - let arch_dir = latest_version_dir.join(arch); - let Some(runtime_dir) = glob::glob(&glob_path(&arch_dir, "Microsoft.VC*.CRT"))? - .filter_map(Result::ok) - .find(|path| path.is_dir()) - else { - return Err(crate::Error::GenericError(format!( - "failed to find Visual C++ runtime directory for `{arch}` in `{}`", - arch_dir.display() - ))); - }; - - Ok(runtime_dir) -} - -fn latest_vc_redist_version_dir(redist_dir: &Path) -> crate::Result> { - let dir = fs::read_dir(redist_dir)? - .flatten() - .map(|entry| entry.path()) - .filter(|path| path.is_dir()) - .filter_map(|path| { - let version = path - .file_name()? - .to_str()? - .parse::() - .ok()?; - Some((version, path)) - }) - .max_by(|(a, _), (b, _)| a.cmp(b)) - .map(|(_, path)| path); - Ok(dir) -} - -/// Builds a glob pattern from a literal base path and an unescaped glob suffix. -/// -/// The base path is escaped so Visual Studio paths containing glob metacharacters are treated as -/// literal directories, while `pattern` remains active glob syntax. -fn glob_path(path: &Path, pattern: &str) -> String { - PathBuf::from(glob::Pattern::escape(&path.to_string_lossy())) - .join(pattern) - .to_string_lossy() - .into_owned() -} - -/// Returns the bundled `vswhere.exe` path. -/// -/// The executable is written to a temporary file so callers do not depend on a system-installed -/// `vswhere.exe`. -pub fn vswhere_path() -> Option { - let mut vswhere = std::env::temp_dir(); - vswhere.push("vswhere.exe"); - - if !vswhere.exists() { - let mut file = std::fs::File::create(&vswhere).ok()?; - file.write_all(VSWHERE).ok()?; - } - - Some(vswhere) -} - #[cfg(target_os = "windows")] pub fn processor_architecture<'a>() -> Option<&'a str> { use windows_sys::Win32::System::SystemInformation::{ diff --git a/crates/tauri-bundler/src/error.rs b/crates/tauri-bundler/src/error.rs index 211b5148dcd9..40547a3eea39 100644 --- a/crates/tauri-bundler/src/error.rs +++ b/crates/tauri-bundler/src/error.rs @@ -79,11 +79,11 @@ pub enum Error { #[error("`{0}`")] HttpError(#[from] Box), /// Invalid glob pattern. - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] + #[cfg(windows)] #[error("{0}")] GlobPattern(#[from] glob::PatternError), /// Failed to use glob pattern. - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] + #[cfg(windows)] #[error("`{0}`")] Glob(#[from] glob::GlobError), /// Failed to parse the URL diff --git a/crates/tauri-cli/ENVIRONMENT_VARIABLES.md b/crates/tauri-cli/ENVIRONMENT_VARIABLES.md index f6f400ff7678..5a8a18100a18 100644 --- a/crates/tauri-cli/ENVIRONMENT_VARIABLES.md +++ b/crates/tauri-cli/ENVIRONMENT_VARIABLES.md @@ -24,8 +24,6 @@ These environment variables are inputs to the CLI which may have an equivalent C - `TAURI_SIGNING_RPM_KEY` — The private GPG key used to sign the RPM bundle, exported to its ASCII-armored format. - `TAURI_SIGNING_RPM_KEY_PASSPHRASE` — The GPG key passphrase for `TAURI_SIGNING_RPM_KEY`, if needed. - `TAURI_WINDOWS_SIGNTOOL_PATH` — Specify a path to `signtool.exe` used for code signing the application on Windows. -- `STATIC_VCRUNTIME` — Deprecated. Set `build > windows > staticVCRuntime` in `tauri.conf.json` instead. -- `VCTOOLS_REDIST_DIR` — Override the Visual C++ redistributable root directory used when `bundle > windows > bundleVCRuntime` is enabled. If unset, Tauri uses its bundled `vswhere.exe` to locate Visual Studio and derive this directory. - `APPLE_CERTIFICATE` — Base64 encoded of the `.p12` certificate for code signing. To get this value, run `openssl base64 -in MyCertificate.p12 -out MyCertificate-base64.txt`. - `APPLE_CERTIFICATE_PASSWORD` — The password you used to export the certificate. - `APPLE_ID` — The Apple ID used to notarize the application. If this environment variable is provided, `APPLE_PASSWORD` and `APPLE_TEAM_ID` must also be set. Alternatively, `APPLE_API_KEY` and `APPLE_API_ISSUER` can be used to authenticate. diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index 64a7109d95cc..dbbd5dff137e 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -71,10 +71,7 @@ "description": "The build configuration.", "default": { "additionalWatchFolders": [], - "removeUnusedCommands": false, - "windows": { - "staticVCRuntime": true - } + "removeUnusedCommands": false }, "allOf": [ { @@ -132,7 +129,6 @@ "useLocalToolsDir": false, "windows": { "allowDowngrades": true, - "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -1975,17 +1971,6 @@ "items": { "type": "string" } - }, - "windows": { - "description": "Windows-specific build configuration.", - "default": { - "staticVCRuntime": true - }, - "allOf": [ - { - "$ref": "#/definitions/WindowsBuildConfig" - } - ] } }, "additionalProperties": false @@ -2113,18 +2098,6 @@ } ] }, - "WindowsBuildConfig": { - "description": "Windows-specific build configuration.", - "type": "object", - "properties": { - "staticVCRuntime": { - "description": "Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets.", - "default": true, - "type": "boolean" - } - }, - "additionalProperties": false - }, "BundleConfig": { "description": "Configuration for tauri-bundler.\n\n See more: ", "type": "object", @@ -2256,7 +2229,6 @@ "description": "Configuration for the Windows bundles.", "default": { "allowDowngrades": true, - "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -2777,11 +2749,6 @@ "type": "null" } ] - }, - "bundleVCRuntime": { - "description": "Whether to bundle the Visual C++ runtime DLLs alongside the application.\n\n This can be particularly useful when your application includes sidecars or DLLs that do\n not statically link the Visual C++ runtime and require the runtime DLLs at runtime, and\n you do not want to require users to install the Visual C++ Redistributable. This can also\n be useful when `build > windows > staticVCRuntime` is set to `false`.", - "default": false, - "type": "boolean" } }, "additionalProperties": false diff --git a/crates/tauri-bundler/src/bundle/windows/vswhere.exe b/crates/tauri-cli/scripts/vswhere.exe similarity index 100% rename from crates/tauri-bundler/src/bundle/windows/vswhere.exe rename to crates/tauri-cli/scripts/vswhere.exe diff --git a/crates/tauri-cli/src/info/env_system.rs b/crates/tauri-cli/src/info/env_system.rs index fb429c0db8f5..0087319eb820 100644 --- a/crates/tauri-cli/src/info/env_system.rs +++ b/crates/tauri-cli/src/info/env_system.rs @@ -17,10 +17,20 @@ struct VsInstanceInfo { display_name: String, } +#[cfg(windows)] +const VSWHERE: &[u8] = include_bytes!("../../scripts/vswhere.exe"); + #[cfg(windows)] fn build_tools_version() -> crate::Result> { - let vswhere = - tauri_bundler::bundle::vswhere_path().context("failed to find or prepare vswhere.exe")?; + let mut vswhere = std::env::temp_dir(); + vswhere.push("vswhere.exe"); + + if !vswhere.exists() { + if let Ok(mut file) = std::fs::File::create(&vswhere) { + use std::io::Write; + let _ = file.write_all(VSWHERE); + } + } // Check if there are Visual Studio installations that have the "MSVC - C++ Buildtools" and "Windows SDK" components. // Both the Windows 10 and Windows 11 SDKs work so we need to query it twice. diff --git a/crates/tauri-cli/src/interface/rust.rs b/crates/tauri-cli/src/interface/rust.rs index 0b76a19ba0d7..e18e8308f444 100644 --- a/crates/tauri-cli/src/interface/rust.rs +++ b/crates/tauri-cli/src/interface/rust.rs @@ -1658,7 +1658,6 @@ fn tauri_config_to_bundle_settings( allow_downgrades: config.windows.allow_downgrades, sign_command: config.windows.sign_command.map(custom_sign_settings), minimum_webview2_version: config.windows.minimum_webview2_version, - bundle_vc_runtime: config.windows.bundle_vc_runtime, }, license: config.license.or_else(|| { settings diff --git a/crates/tauri-cli/src/interface/rust/desktop.rs b/crates/tauri-cli/src/interface/rust/desktop.rs index ed252fb10c83..ddde0a4f0a44 100644 --- a/crates/tauri-cli/src/interface/rust/desktop.rs +++ b/crates/tauri-cli/src/interface/rust/desktop.rs @@ -159,6 +159,10 @@ pub fn build( let out_dir = app_settings.out_dir(&options, tauri_dir)?; let bin_path = app_settings.app_binary_path(&options, tauri_dir)?; + if !std::env::var_os("STATIC_VCRUNTIME").is_some_and(|v| v == "false") { + std::env::set_var("STATIC_VCRUNTIME", "true"); + } + if options.target == Some("universal-apple-darwin".into()) { std::fs::create_dir_all(&out_dir) .fs_context("failed to create project out directory", out_dir.clone())?; diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index 64a7109d95cc..dbbd5dff137e 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -71,10 +71,7 @@ "description": "The build configuration.", "default": { "additionalWatchFolders": [], - "removeUnusedCommands": false, - "windows": { - "staticVCRuntime": true - } + "removeUnusedCommands": false }, "allOf": [ { @@ -132,7 +129,6 @@ "useLocalToolsDir": false, "windows": { "allowDowngrades": true, - "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -1975,17 +1971,6 @@ "items": { "type": "string" } - }, - "windows": { - "description": "Windows-specific build configuration.", - "default": { - "staticVCRuntime": true - }, - "allOf": [ - { - "$ref": "#/definitions/WindowsBuildConfig" - } - ] } }, "additionalProperties": false @@ -2113,18 +2098,6 @@ } ] }, - "WindowsBuildConfig": { - "description": "Windows-specific build configuration.", - "type": "object", - "properties": { - "staticVCRuntime": { - "description": "Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets.", - "default": true, - "type": "boolean" - } - }, - "additionalProperties": false - }, "BundleConfig": { "description": "Configuration for tauri-bundler.\n\n See more: ", "type": "object", @@ -2256,7 +2229,6 @@ "description": "Configuration for the Windows bundles.", "default": { "allowDowngrades": true, - "bundleVCRuntime": false, "certificateThumbprint": null, "digestAlgorithm": null, "minimumWebview2Version": null, @@ -2777,11 +2749,6 @@ "type": "null" } ] - }, - "bundleVCRuntime": { - "description": "Whether to bundle the Visual C++ runtime DLLs alongside the application.\n\n This can be particularly useful when your application includes sidecars or DLLs that do\n not statically link the Visual C++ runtime and require the runtime DLLs at runtime, and\n you do not want to require users to install the Visual C++ Redistributable. This can also\n be useful when `build > windows > staticVCRuntime` is set to `false`.", - "default": false, - "type": "boolean" } }, "additionalProperties": false diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index f5483f3b96a1..a54c619e3f6f 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -1078,19 +1078,6 @@ pub struct WindowsConfig { /// need to use another tool like `osslsigncode`. #[serde(alias = "sign-command")] pub sign_command: Option, - /// Whether to bundle the Visual C++ runtime DLLs alongside the application. - /// - /// This can be particularly useful when your application includes sidecars or DLLs that do - /// not statically link the Visual C++ runtime and require the runtime DLLs at runtime, and - /// you do not want to require users to install the Visual C++ Redistributable. This can also - /// be useful when `build > windows > staticVCRuntime` is set to `false`. - #[serde( - default, - rename = "bundleVCRuntime", - alias = "bundle-vc-runtime", - alias = "bundleVcRuntime" - )] - pub bundle_vc_runtime: bool, } impl Default for WindowsConfig { @@ -1106,7 +1093,6 @@ impl Default for WindowsConfig { wix: None, nsis: None, sign_command: None, - bundle_vc_runtime: false, } } } @@ -3462,32 +3448,6 @@ pub struct BuildConfig { /// Additional paths to watch for changes when running `tauri dev`. #[serde(alias = "additional-watch-directories", default)] pub additional_watch_folders: Vec, - /// Windows-specific build configuration. - #[serde(default)] - pub windows: WindowsBuildConfig, -} - -/// Windows-specific build configuration. -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] -#[cfg_attr(feature = "schema", derive(JsonSchema))] -#[serde(rename_all = "camelCase", deny_unknown_fields)] -pub struct WindowsBuildConfig { - /// Whether to statically link the Visual C++ runtime into the application binary on Windows MSVC targets. - #[serde( - default = "default_true", - rename = "staticVCRuntime", - alias = "static-vc-runtime", - alias = "staticVcRuntime" - )] - pub static_vc_runtime: bool, -} - -impl Default for WindowsBuildConfig { - fn default() -> Self { - Self { - static_vc_runtime: true, - } - } } #[derive(Debug, PartialEq, Eq)] @@ -4166,7 +4126,6 @@ mod build { let features = quote!(None); let remove_unused_commands = quote!(false); let additional_watch_folders = quote!(Vec::new()); - let windows = &self.windows; literal_struct!( tokens, @@ -4179,20 +4138,7 @@ mod build { before_bundle_command, features, remove_unused_commands, - additional_watch_folders, - windows - ); - } - } - - impl ToTokens for WindowsBuildConfig { - fn to_tokens(&self, tokens: &mut TokenStream) { - let static_vc_runtime = self.static_vc_runtime; - - literal_struct!( - tokens, - ::tauri::utils::config::WindowsBuildConfig, - static_vc_runtime + additional_watch_folders ); } } @@ -4536,7 +4482,6 @@ mod test { features: None, remove_unused_commands: false, additional_watch_folders: Vec::new(), - windows: WindowsBuildConfig::default(), }; // create a bundle config From 499df79be65ef8c0670abc0207cd9e37b55d8491 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 00:24:30 +0800 Subject: [PATCH 08/15] apply version updates (#15378) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .changes/fix-window-menu-nsapp-command.md | 5 --- .changes/no-dest-resource-target.md | 17 ---------- .changes/resources-after-empty-diretory.md | 18 ----------- Cargo.lock | 26 +++++++-------- crates/tauri-build/CHANGELOG.md | 7 ++++ crates/tauri-build/Cargo.toml | 6 ++-- crates/tauri-bundler/CHANGELOG.md | 6 ++++ crates/tauri-bundler/Cargo.toml | 4 +-- crates/tauri-cli/CHANGELOG.md | 7 ++++ crates/tauri-cli/Cargo.toml | 6 ++-- crates/tauri-cli/config.schema.json | 2 +- crates/tauri-cli/metadata-v2.json | 8 ++--- crates/tauri-codegen/CHANGELOG.md | 6 ++++ crates/tauri-codegen/Cargo.toml | 4 +-- crates/tauri-macros/CHANGELOG.md | 7 ++++ crates/tauri-macros/Cargo.toml | 6 ++-- crates/tauri-plugin/CHANGELOG.md | 6 ++++ crates/tauri-plugin/Cargo.toml | 4 +-- crates/tauri-runtime-wry/CHANGELOG.md | 7 ++++ crates/tauri-runtime-wry/Cargo.toml | 6 ++-- crates/tauri-runtime/CHANGELOG.md | 6 ++++ crates/tauri-runtime/Cargo.toml | 4 +-- .../schemas/config.schema.json | 2 +- crates/tauri-utils/CHANGELOG.md | 32 +++++++++++++++++++ crates/tauri-utils/Cargo.toml | 2 +- crates/tauri/CHANGELOG.md | 14 ++++++++ crates/tauri/Cargo.toml | 14 ++++---- packages/cli/CHANGELOG.md | 6 ++++ packages/cli/package.json | 2 +- 29 files changed, 152 insertions(+), 88 deletions(-) delete mode 100644 .changes/fix-window-menu-nsapp-command.md delete mode 100644 .changes/no-dest-resource-target.md delete mode 100644 .changes/resources-after-empty-diretory.md diff --git a/.changes/fix-window-menu-nsapp-command.md b/.changes/fix-window-menu-nsapp-command.md deleted file mode 100644 index 22ef6a3d910b..000000000000 --- a/.changes/fix-window-menu-nsapp-command.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": "patch:bug" ---- - -Fixed `Submenu.setAsWindowsMenuForNSApp()` calling the Help menu setter instead of the Window menu setter. diff --git a/.changes/no-dest-resource-target.md b/.changes/no-dest-resource-target.md deleted file mode 100644 index 926b8e8c8cf3..000000000000 --- a/.changes/no-dest-resource-target.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"tauri-utils": "patch:bug" ---- - -Fix a regression in tauri-utils 2.8.3 that made empty path an invalid resource target, e.g. - -```json -{ - "bundle": { - "resources": { - "README.md": "", - } - } -} -``` - -(this means `README.md` -> `$RESOURCE/README.md`, note this is a confusing behavior, and will be changed in v3) diff --git a/.changes/resources-after-empty-diretory.md b/.changes/resources-after-empty-diretory.md deleted file mode 100644 index 58087ef0b68b..000000000000 --- a/.changes/resources-after-empty-diretory.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -"tauri-utils": "patch:bug" ---- - -Fix a regression in tauri-utils 2.8.3 that made an empty directory makes it skip all the following entries, e.g. - -```json -{ - "bundle": { - "resources": [ - "empty-directory", - "README.md" - ] - } -} -``` - -if `empty-directory` is empty, the `README.md` will not be copied to the resource directory (skipped) diff --git a/Cargo.lock b/Cargo.lock index bd6659c89090..efd61396f5d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1321,7 +1321,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -5540,7 +5540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] @@ -8784,7 +8784,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.11.1" +version = "2.11.2" dependencies = [ "anyhow", "bytes", @@ -8845,7 +8845,7 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.6.1" +version = "2.6.2" dependencies = [ "anyhow", "cargo_toml", @@ -8866,7 +8866,7 @@ dependencies = [ [[package]] name = "tauri-bundler" -version = "2.9.1" +version = "2.9.2" dependencies = [ "anyhow", "ar", @@ -8912,7 +8912,7 @@ dependencies = [ [[package]] name = "tauri-cli" -version = "2.11.1" +version = "2.11.2" dependencies = [ "ar", "axum", @@ -9006,7 +9006,7 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.6.1" +version = "2.6.2" dependencies = [ "base64 0.22.1", "brotli", @@ -9094,7 +9094,7 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.6.1" +version = "2.6.2" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -9106,7 +9106,7 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.6.1" +version = "2.6.2" dependencies = [ "anyhow", "glob", @@ -9153,7 +9153,7 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.11.1" +version = "2.11.2" dependencies = [ "cookie", "dpi", @@ -9176,7 +9176,7 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.11.1" +version = "2.11.2" dependencies = [ "gtk", "http 1.3.1", @@ -9226,7 +9226,7 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.9.1" +version = "2.9.2" dependencies = [ "aes-gcm", "anyhow", @@ -10654,7 +10654,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/crates/tauri-build/CHANGELOG.md b/crates/tauri-build/CHANGELOG.md index df654d6eda9f..fb80c0cdf3ee 100644 --- a/crates/tauri-build/CHANGELOG.md +++ b/crates/tauri-build/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## \[2.6.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` +- Upgraded to `tauri-codegen@2.6.2` + ## \[2.6.1] ### Dependencies diff --git a/crates/tauri-build/Cargo.toml b/crates/tauri-build/Cargo.toml index 78e9b1551522..8061a8f2c3a3 100644 --- a/crates/tauri-build/Cargo.toml +++ b/crates/tauri-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-build" -version = "2.6.1" +version = "2.6.2" description = "build time code to pair with https://crates.io/crates/tauri" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -26,8 +26,8 @@ targets = [ [dependencies] anyhow = "1" quote = { version = "1", optional = true } -tauri-codegen = { version = "2.6.1", path = "../tauri-codegen", optional = true } -tauri-utils = { version = "2.9.1", path = "../tauri-utils", features = [ +tauri-codegen = { version = "2.6.2", path = "../tauri-codegen", optional = true } +tauri-utils = { version = "2.9.2", path = "../tauri-utils", features = [ "build-2", "resources", ] } diff --git a/crates/tauri-bundler/CHANGELOG.md b/crates/tauri-bundler/CHANGELOG.md index 31a0e7f95a1f..c86a769b304b 100644 --- a/crates/tauri-bundler/CHANGELOG.md +++ b/crates/tauri-bundler/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## \[2.9.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` + ## \[2.9.1] ### Dependencies diff --git a/crates/tauri-bundler/Cargo.toml b/crates/tauri-bundler/Cargo.toml index 5dc1cdb117b3..a32aa0007858 100644 --- a/crates/tauri-bundler/Cargo.toml +++ b/crates/tauri-bundler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-bundler" -version = "2.9.1" +version = "2.9.2" authors = [ "George Burton ", "Tauri Programme within The Commons Conservancy", @@ -15,7 +15,7 @@ rust-version = "1.77.2" exclude = ["CHANGELOG.md", "/target", "rustfmt.toml"] [dependencies] -tauri-utils = { version = "2.9.1", path = "../tauri-utils", features = [ +tauri-utils = { version = "2.9.2", path = "../tauri-utils", features = [ "resources", ] } image = "0.25" diff --git a/crates/tauri-cli/CHANGELOG.md b/crates/tauri-cli/CHANGELOG.md index 66b7b7d8f4ea..03b4ca37d59c 100644 --- a/crates/tauri-cli/CHANGELOG.md +++ b/crates/tauri-cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## \[2.11.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` +- Upgraded to `tauri-bundler@2.9.2` + ## \[2.11.1] ### Dependencies diff --git a/crates/tauri-cli/Cargo.toml b/crates/tauri-cli/Cargo.toml index 97d9409a730c..877394237347 100644 --- a/crates/tauri-cli/Cargo.toml +++ b/crates/tauri-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-cli" -version = "2.11.1" +version = "2.11.2" authors = ["Tauri Programme within The Commons Conservancy"] edition = "2021" rust-version = "1.77.2" @@ -47,7 +47,7 @@ sublime_fuzzy = "0.7" clap_complete = "4" clap = { version = "4", features = ["derive", "env"] } thiserror = "2" -tauri-bundler = { version = "2.9.1", default-features = false, path = "../tauri-bundler" } +tauri-bundler = { version = "2.9.2", default-features = false, path = "../tauri-bundler" } colored = "2" serde = { version = "1", features = ["derive"] } serde_json = { version = "1", features = ["preserve_order"] } @@ -58,7 +58,7 @@ shared_child = "1" duct = "1.0" toml_edit = { version = "0.25", features = ["serde"] } json-patch = "3" -tauri-utils = { version = "2.9.1", path = "../tauri-utils", features = [ +tauri-utils = { version = "2.9.2", path = "../tauri-utils", features = [ "isolation", "schema", "config-json5", diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index dbbd5dff137e..898317a465a0 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://schema.tauri.app/config/2.11.1", + "$id": "https://schema.tauri.app/config/2.11.2", "title": "Config", "description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"http://localhost:3000\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```", "type": "object", diff --git a/crates/tauri-cli/metadata-v2.json b/crates/tauri-cli/metadata-v2.json index 091d891cd366..9484a7df7caa 100644 --- a/crates/tauri-cli/metadata-v2.json +++ b/crates/tauri-cli/metadata-v2.json @@ -1,9 +1,9 @@ { "cli.js": { - "version": "2.11.1", + "version": "2.11.2", "node": ">= 10.0.0" }, - "tauri": "2.11.1", - "tauri-build": "2.6.1", - "tauri-plugin": "2.6.1" + "tauri": "2.11.2", + "tauri-build": "2.6.2", + "tauri-plugin": "2.6.2" } diff --git a/crates/tauri-codegen/CHANGELOG.md b/crates/tauri-codegen/CHANGELOG.md index fa8c1c97352d..a445a96af25a 100644 --- a/crates/tauri-codegen/CHANGELOG.md +++ b/crates/tauri-codegen/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## \[2.6.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` + ## \[2.6.1] ### Dependencies diff --git a/crates/tauri-codegen/Cargo.toml b/crates/tauri-codegen/Cargo.toml index 5f49642cbb78..9f23170ebc8a 100644 --- a/crates/tauri-codegen/Cargo.toml +++ b/crates/tauri-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-codegen" -version = "2.6.1" +version = "2.6.2" description = "code generation meant to be consumed inside of `tauri` through `tauri-build` or `tauri-macros`" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -20,7 +20,7 @@ quote = "1" syn = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" -tauri-utils = { version = "2.9.1", path = "../tauri-utils", features = [ +tauri-utils = { version = "2.9.2", path = "../tauri-utils", features = [ "build-2", ] } thiserror = "2" diff --git a/crates/tauri-macros/CHANGELOG.md b/crates/tauri-macros/CHANGELOG.md index 2e3ec6a59577..1058cdb099b1 100644 --- a/crates/tauri-macros/CHANGELOG.md +++ b/crates/tauri-macros/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## \[2.6.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` +- Upgraded to `tauri-codegen@2.6.2` + ## \[2.6.1] ### Dependencies diff --git a/crates/tauri-macros/Cargo.toml b/crates/tauri-macros/Cargo.toml index 69e7f3891684..8b50579b6db1 100644 --- a/crates/tauri-macros/Cargo.toml +++ b/crates/tauri-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-macros" -version = "2.6.1" +version = "2.6.2" description = "Macros for the tauri crate." exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -20,8 +20,8 @@ proc-macro2 = { version = "1", features = ["span-locations"] } quote = "1" syn = { version = "2", features = ["full"] } heck = "0.5" -tauri-codegen = { version = "2.6.1", default-features = false, path = "../tauri-codegen" } -tauri-utils = { version = "2.9.1", path = "../tauri-utils" } +tauri-codegen = { version = "2.6.2", default-features = false, path = "../tauri-codegen" } +tauri-utils = { version = "2.9.2", path = "../tauri-utils" } [features] custom-protocol = [] diff --git a/crates/tauri-plugin/CHANGELOG.md b/crates/tauri-plugin/CHANGELOG.md index 8667ba6939ac..b721b377ca6c 100644 --- a/crates/tauri-plugin/CHANGELOG.md +++ b/crates/tauri-plugin/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## \[2.6.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` + ## \[2.6.1] ### Dependencies diff --git a/crates/tauri-plugin/Cargo.toml b/crates/tauri-plugin/Cargo.toml index f169d51852f9..496c3500c97c 100644 --- a/crates/tauri-plugin/Cargo.toml +++ b/crates/tauri-plugin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-plugin" -version = "2.6.1" +version = "2.6.2" description = "Build script and runtime Tauri plugin definitions" authors.workspace = true homepage.workspace = true @@ -27,7 +27,7 @@ runtime = [] [dependencies] anyhow = { version = "1", optional = true } serde = { version = "1", optional = true } -tauri-utils = { version = "2.9.1", default-features = false, features = [ +tauri-utils = { version = "2.9.2", default-features = false, features = [ "build-2", ], path = "../tauri-utils" } serde_json = { version = "1", optional = true } diff --git a/crates/tauri-runtime-wry/CHANGELOG.md b/crates/tauri-runtime-wry/CHANGELOG.md index 3f31a89f6380..8dacff6c100e 100644 --- a/crates/tauri-runtime-wry/CHANGELOG.md +++ b/crates/tauri-runtime-wry/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## \[2.11.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` +- Upgraded to `tauri-runtime@2.11.2` + ## \[2.11.1] ### Dependencies diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml index 219336a9e479..d74e82031e19 100644 --- a/crates/tauri-runtime-wry/Cargo.toml +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-runtime-wry" -version = "2.11.1" +version = "2.11.2" description = "Wry bindings to the Tauri runtime" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -19,8 +19,8 @@ wry = { version = "0.55.0", default-features = false, features = [ "linux-body", ] } tao = { version = "0.35.0", default-features = false, features = ["rwh_06"] } -tauri-runtime = { version = "2.11.1", path = "../tauri-runtime" } -tauri-utils = { version = "2.9.1", path = "../tauri-utils" } +tauri-runtime = { version = "2.11.2", path = "../tauri-runtime" } +tauri-utils = { version = "2.9.2", path = "../tauri-utils" } raw-window-handle = "0.6" http = "1" url = "2" diff --git a/crates/tauri-runtime/CHANGELOG.md b/crates/tauri-runtime/CHANGELOG.md index bbcb4bd54e71..fab7ce5bb382 100644 --- a/crates/tauri-runtime/CHANGELOG.md +++ b/crates/tauri-runtime/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## \[2.11.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` + ## \[2.11.1] ### Dependencies diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml index 48a1c0b4ae31..7b73df4588f6 100644 --- a/crates/tauri-runtime/Cargo.toml +++ b/crates/tauri-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-runtime" -version = "2.11.1" +version = "2.11.2" description = "Runtime for Tauri applications" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -27,7 +27,7 @@ targets = [ serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "2" -tauri-utils = { version = "2.9.1", path = "../tauri-utils" } +tauri-utils = { version = "2.9.2", path = "../tauri-utils" } http = "1" raw-window-handle = "0.6" url = { version = "2" } diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index dbbd5dff137e..898317a465a0 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://schema.tauri.app/config/2.11.1", + "$id": "https://schema.tauri.app/config/2.11.2", "title": "Config", "description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"http://localhost:3000\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```", "type": "object", diff --git a/crates/tauri-utils/CHANGELOG.md b/crates/tauri-utils/CHANGELOG.md index dc7ed0537832..435dc48706c7 100644 --- a/crates/tauri-utils/CHANGELOG.md +++ b/crates/tauri-utils/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## \[2.9.2] + +### Bug Fixes + +- [`b5b72ce51`](https://www.github.com/tauri-apps/tauri/commit/b5b72ce51811e9f95b1f7e9a05ea19c8f12ce694) ([#15383](https://www.github.com/tauri-apps/tauri/pull/15383) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix a regression in tauri-utils 2.8.3 that made empty path an invalid resource target, e.g. + + ```json + { + "bundle": { + "resources": { + "README.md": "", + } + } + } + ``` + + (this means `README.md` -> `$RESOURCE/README.md`, note this is a confusing behavior, and will be changed in v3) +- [`3fd8ba2c0`](https://www.github.com/tauri-apps/tauri/commit/3fd8ba2c022717068ff6a154ce12942c3a672232) ([#15388](https://www.github.com/tauri-apps/tauri/pull/15388) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix a regression in tauri-utils 2.8.3 that made an empty directory makes it skip all the following entries, e.g. + + ```json + { + "bundle": { + "resources": [ + "empty-directory", + "README.md" + ] + } + } + ``` + + if `empty-directory` is empty, the `README.md` will not be copied to the resource directory (skipped) + ## \[2.9.1] ### Dependencies diff --git a/crates/tauri-utils/Cargo.toml b/crates/tauri-utils/Cargo.toml index 2f0ae3c0efdd..7f39104d797c 100644 --- a/crates/tauri-utils/Cargo.toml +++ b/crates/tauri-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-utils" -version = "2.9.1" +version = "2.9.2" description = "Utilities for Tauri" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" diff --git a/crates/tauri/CHANGELOG.md b/crates/tauri/CHANGELOG.md index 0803ad1a511c..b709e89f0c0b 100644 --- a/crates/tauri/CHANGELOG.md +++ b/crates/tauri/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## \[2.11.2] + +### Bug Fixes + +- [`47e1b7549`](https://www.github.com/tauri-apps/tauri/commit/47e1b754951bffeedbcd6400928d60755fb954de) ([#15386](https://www.github.com/tauri-apps/tauri/pull/15386) by [@DominikPeters](https://www.github.com/tauri-apps/tauri/../../DominikPeters)) Fixed `Submenu.setAsWindowsMenuForNSApp()` calling the Help menu setter instead of the Window menu setter. + +### Dependencies + +- Upgraded to `tauri-utils@2.9.2` +- Upgraded to `tauri-runtime@2.11.2` +- Upgraded to `tauri-runtime-wry@2.11.2` +- Upgraded to `tauri-macros@2.6.2` +- Upgraded to `tauri-build@2.6.2` + ## \[2.11.1] ### Enhancements diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index 7e6a3669de25..4c2a84ee35fb 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri" -version = "2.11.1" +version = "2.11.2" description = "Make tiny, secure apps for all desktop platforms with Tauri" exclude = ["/test", "/.scripts", "CHANGELOG.md", "/target"] readme = "README.md" @@ -56,12 +56,12 @@ uuid = { version = "1", features = ["v4"], optional = true } url = "2" anyhow = "1" thiserror = "2" -tauri-runtime = { version = "2.11.1", path = "../tauri-runtime" } -tauri-macros = { version = "2.6.1", path = "../tauri-macros" } -tauri-utils = { version = "2.9.1", features = [ +tauri-runtime = { version = "2.11.2", path = "../tauri-runtime" } +tauri-macros = { version = "2.6.2", path = "../tauri-macros" } +tauri-utils = { version = "2.9.2", features = [ "resources", ], path = "../tauri-utils" } -tauri-runtime-wry = { version = "2.11.1", path = "../tauri-runtime-wry", default-features = false, optional = true } +tauri-runtime-wry = { version = "2.11.2", path = "../tauri-runtime-wry", default-features = false, optional = true } getrandom = "0.3" serde_repr = "0.1" http = "1" @@ -168,8 +168,8 @@ objc2-ui-kit = { version = "0.3.0", default-features = false, features = [ [build-dependencies] glob = "0.3" heck = "0.5" -tauri-build = { path = "../tauri-build/", default-features = false, version = "2.6.1" } -tauri-utils = { path = "../tauri-utils/", version = "2.9.1", features = [ +tauri-build = { path = "../tauri-build/", default-features = false, version = "2.6.2" } +tauri-utils = { path = "../tauri-utils/", version = "2.9.2", features = [ "build-2", ] } diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 23d2df879996..6c89dbbd5c1b 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## \[2.11.2] + +### Dependencies + +- Upgraded to `tauri-cli@2.11.2` + ## \[2.11.1] ### Dependencies diff --git a/packages/cli/package.json b/packages/cli/package.json index 71e70da4653c..5830278fb99b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@tauri-apps/cli", - "version": "2.11.1", + "version": "2.11.2", "description": "Command line interface for building Tauri apps", "type": "commonjs", "funding": { From 413f01c065506b81059f452123c71c552ccaa7e4 Mon Sep 17 00:00:00 2001 From: Sean Kenneth Doherty Date: Sun, 17 May 2026 22:17:06 -0500 Subject: [PATCH 09/15] enhance(bundler): add more NSIS path error contexts (#15403) * fix(bundler): clarify nsis config path errors * Address NSIS path context review * Fix NSIS test module order * Address NSIS review comments * Add more `fs_context`s --------- Co-authored-by: Tony --- .changes/nsis-config-path-context.md | 5 +++ .../src/bundle/windows/nsis/mod.rs | 36 +++++++++++++++---- 2 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 .changes/nsis-config-path-context.md diff --git a/.changes/nsis-config-path-context.md b/.changes/nsis-config-path-context.md new file mode 100644 index 000000000000..0166e9c2961e --- /dev/null +++ b/.changes/nsis-config-path-context.md @@ -0,0 +1,5 @@ +--- +"tauri-bundler": "patch:enhance" +--- + +Improve NSIS configuration path errors so missing installer icons and images include the related config key and path. diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs index 0ad87c188cab..1005b882f679 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -319,7 +319,8 @@ fn build_nsis_app_installer( ); if let Some(license_file) = settings.license_file() { - let license_file = dunce::canonicalize(license_file)?; + let license_file = dunce::canonicalize(&license_file) + .fs_context("failed to resolve `bundle > licenseFile`", license_file)?; let license_file_with_bom = output_path.join("license_file"); let content = std::fs::read(license_file)?; write_utf8_with_bom(&license_file_with_bom, content)?; @@ -339,37 +340,58 @@ fn build_nsis_app_installer( if let Some(installer_icon) = &nsis.installer_icon { data.insert( "installer_icon", - to_json(dunce::canonicalize(installer_icon)?), + to_json(dunce::canonicalize(installer_icon).fs_context( + "failed to resolve `bundle > windows > nsis > installerIcon`", + installer_icon.to_owned(), + )?), ); } if let Some(header_image) = &nsis.header_image { - data.insert("header_image", to_json(dunce::canonicalize(header_image)?)); + data.insert( + "header_image", + to_json(dunce::canonicalize(header_image).fs_context( + "failed to resolve `bundle > windows > nsis > headerImage`", + header_image.to_owned(), + )?), + ); } if let Some(sidebar_image) = &nsis.sidebar_image { data.insert( "sidebar_image", - to_json(dunce::canonicalize(sidebar_image)?), + to_json(dunce::canonicalize(sidebar_image).fs_context( + "failed to resolve `bundle > windows > nsis > sidebarImage`", + sidebar_image.to_owned(), + )?), ); } if let Some(uninstaller_icon) = &nsis.uninstaller_icon { data.insert( "uninstaller_icon", - to_json(dunce::canonicalize(uninstaller_icon)?), + to_json(dunce::canonicalize(uninstaller_icon).fs_context( + "failed to resolve `bundle > windows > nsis > uninstallerIcon`", + uninstaller_icon.to_owned(), + )?), ); } if let Some(uninstaller_header_image) = &nsis.uninstaller_header_image { data.insert( "uninstaller_header_image", - to_json(dunce::canonicalize(uninstaller_header_image)?), + to_json(dunce::canonicalize(uninstaller_header_image).fs_context( + "failed to resolve `bundle > windows > nsis > uninstallerHeaderImage`", + uninstaller_header_image.to_owned(), + )?), ); } if let Some(installer_hooks) = &nsis.installer_hooks { - let installer_hooks = dunce::canonicalize(installer_hooks)?; + let installer_hooks = dunce::canonicalize(installer_hooks).fs_context( + "failed to resolve `bundle > windows > nsis > installerHooks`", + installer_hooks.to_owned(), + )?; data.insert("installer_hooks", to_json(installer_hooks)); } From c8cbb82a669d15cfb63cdc090e310d15fe26fc69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 09:55:51 +0800 Subject: [PATCH 10/15] chore(deps): bump brace-expansion from 5.0.5 to 5.0.6 (#15414) Bumps [brace-expansion](https://github.com/juliangruber/brace-expansion) from 5.0.5 to 5.0.6. - [Release notes](https://github.com/juliangruber/brace-expansion/releases) - [Commits](https://github.com/juliangruber/brace-expansion/compare/v5.0.5...v5.0.6) --- updated-dependencies: - dependency-name: brace-expansion dependency-version: 5.0.6 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pnpm-lock.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4875aff5cf5..837829dc8348 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1796,8 +1796,8 @@ packages: blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} engines: {node: 18 || 20 || >=22} braces@3.0.3: @@ -4147,7 +4147,7 @@ snapshots: blake3-wasm@2.1.5: {} - brace-expansion@5.0.5: + brace-expansion@5.0.6: dependencies: balanced-match: 4.0.4 @@ -4570,7 +4570,7 @@ snapshots: minimatch@10.2.5: dependencies: - brace-expansion: 5.0.5 + brace-expansion: 5.0.6 mlly@1.8.0: dependencies: From 41fdca7d1991cf4b4b69a5a758a5371333218487 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 May 2026 11:05:28 +0800 Subject: [PATCH 11/15] chore(deps): bump ws from 8.18.0 to 8.20.1 (via audit fix) (#15417) * chore(deps): bump ws from 8.18.0 to 8.20.1 (via audit fix) Bumps [ws](https://github.com/websockets/ws) from 8.18.0 to 8.20.1. - [Release notes](https://github.com/websockets/ws/releases) - [Commits](https://github.com/websockets/ws/compare/8.18.0...8.20.1) --- updated-dependencies: - dependency-name: ws dependency-version: 8.20.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] * Fix missing override in the commit --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tony --- pnpm-lock.yaml | 11 +++++++---- pnpm-workspace.yaml | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 837829dc8348..ebf53f4c5cd1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,9 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + ws@>=8.0.0 <8.20.1: '>=8.20.1' + importers: .: @@ -2750,8 +2753,8 @@ packages: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -4562,7 +4565,7 @@ snapshots: sharp: 0.34.5 undici: 7.24.4 workerd: 1.20260317.1 - ws: 8.18.0 + ws: 8.20.1 youch: 4.1.0-beta.10 transitivePeerDependencies: - bufferutil @@ -5101,7 +5104,7 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - ws@8.18.0: {} + ws@8.20.1: {} yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f0a696121145..04054138f8ce 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -9,3 +9,6 @@ packages: onlyBuiltDependencies: - esbuild - workerd + +overrides: + ws@>=8.0.0 <8.20.1: '>=8.20.1' From b5b9de2db051599620aa31b375aed678efeb61c1 Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Fri, 22 May 2026 19:08:03 +0800 Subject: [PATCH 12/15] docs: acl `Identifier` is a permission id not plugin id (#15428) --- crates/tauri-utils/src/acl/identifier.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/tauri-utils/src/acl/identifier.rs b/crates/tauri-utils/src/acl/identifier.rs index 26c7326d2c6d..7b9f90f2f4fd 100644 --- a/crates/tauri-utils/src/acl/identifier.rs +++ b/crates/tauri-utils/src/acl/identifier.rs @@ -17,7 +17,10 @@ const MAX_LEN_PREFIX: usize = 64 - PLUGIN_PREFIX.len(); const MAX_LEN_BASE: usize = 64; const MAX_LEN_IDENTIFIER: usize = MAX_LEN_PREFIX + 1 + MAX_LEN_BASE; -/// Plugin identifier. +/// Permission identifier. +/// +/// Typically used in the [`permissions`](crate::acl::Capability::permissions) field of a capability file. +/// (e.g. `core:default`, `sample:allow-ping-scoped`) #[derive(Debug, Clone, PartialEq, Eq)] pub struct Identifier { inner: String, From 2857c01c69459dc8e6c92192afd36420249b7b16 Mon Sep 17 00:00:00 2001 From: Koki Sato Date: Sat, 23 May 2026 10:39:12 +0900 Subject: [PATCH 13/15] fix(nsis): embed signed copies of stock plugins, not unsigned system DLLs (#15422) * fix(nsis): embed signed copies of stock plugins, not unsigned system DLLs * refactor(nsis): hoist !addplugindir above !include to stay ahead of plugin commands --- .changes/nsis-stock-plugins-embed-signed.md | 5 +++++ .../src/bundle/windows/nsis/installer.nsi | 6 ++++++ crates/tauri-bundler/src/bundle/windows/nsis/mod.rs | 11 +++++++---- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 .changes/nsis-stock-plugins-embed-signed.md diff --git a/.changes/nsis-stock-plugins-embed-signed.md b/.changes/nsis-stock-plugins-embed-signed.md new file mode 100644 index 000000000000..dbce16faaef1 --- /dev/null +++ b/.changes/nsis-stock-plugins-embed-signed.md @@ -0,0 +1,5 @@ +--- +"tauri-bundler": "patch:bug" +--- + +Fix NSIS stock plugins (`NSISdl.dll`, `StartMenu.dll`, `System.dll`, `nsDialogs.dll`) being embedded in the final installer as unsigned despite the signing step succeeding. The signed local copies under `/Plugins/x86-unicode/` were not on makensis' plugin search path, so makensis fell back to the unsigned DLLs from the NSIS toolset directory. The fix adds `!addplugindir` for the signed plugin directory before any plugin command is parsed in the script. diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi b/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi index a48a46149f6d..d372e3c39177 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi +++ b/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi @@ -13,6 +13,12 @@ ManifestDPIAwareness PerMonitorV2 SetCompressor /SOLID "{{compression}}" !endif +; Keep above !include to stay ahead of any plugin command +; see https://github.com/tauri-apps/tauri/pull/15422#discussion_r3289239624 +{{#if signed_plugins_path}} +!addplugindir "{{signed_plugins_path}}" +{{/if}} + !include MUI2.nsh !include FileFunc.nsh !include x64.nsh diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs index 1005b882f679..5ee7db5bcaa3 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -282,6 +282,13 @@ fn build_nsis_app_installer( to_json(&additional_plugins_path), ); + if let Some(plugin_copy_path) = &maybe_plugin_copy_path { + data.insert( + "signed_plugins_path", + to_json(plugin_copy_path.join("x86-unicode")), + ); + } + data.insert("arch", to_json(arch)); data.insert("bundle_id", to_json(bundle_id)); data.insert("manufacturer", to_json(manufacturer)); @@ -683,10 +690,6 @@ fn build_nsis_app_installer( #[cfg(not(target_os = "windows"))] let mut nsis_cmd = Command::new("makensis"); - if let Some(plugins_path) = &maybe_plugin_copy_path { - nsis_cmd.env("NSISPLUGINS", plugins_path); - } - nsis_cmd .args(["-INPUTCHARSET", "UTF8", "-OUTPUTCHARSET", "UTF8"]) .arg(match settings.log_level() { From 472f6d01f4b4032c282824a3f7e21a358a71b80c Mon Sep 17 00:00:00 2001 From: Tony <68118705+Legend-Master@users.noreply.github.com> Date: Sat, 23 May 2026 10:08:40 +0800 Subject: [PATCH 14/15] fix: check makensis exit code (#15429) * fix: check makensis exit code * Merge branch 'dev' of https://github.com/tauri-apps/tauri into check-makensis-exit-code --- crates/tauri-bundler/src/bundle/windows/nsis/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs index 5ee7db5bcaa3..67563de153a9 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -13,7 +13,7 @@ use crate::{ }, }, }, - error::ErrorExt, + error::{bail, ErrorExt}, utils::{ http_utils::{download_and_verify, verify_file_hash, HashAlgorithm}, CommandExt, @@ -657,7 +657,7 @@ fn build_nsis_app_installer( ); let nsis_output_path = output_path.join(out_file); - let nsis_installer_path = settings.project_out_directory().to_path_buf().join(format!( + let nsis_installer_path = settings.project_out_directory().join(format!( "bundle/{}/{}.exe", if updater { NSIS_UPDATER_OUTPUT_FOLDER_NAME @@ -690,7 +690,7 @@ fn build_nsis_app_installer( #[cfg(not(target_os = "windows"))] let mut nsis_cmd = Command::new("makensis"); - nsis_cmd + let status = nsis_cmd .args(["-INPUTCHARSET", "UTF8", "-OUTPUTCHARSET", "UTF8"]) .arg(match settings.log_level() { log::Level::Error => "-V1", @@ -707,6 +707,9 @@ fn build_nsis_app_installer( command: "makensis.exe".to_string(), error, })?; + if !status.success() { + bail!("Failed to bundle app with makensis"); + } fs::rename(nsis_output_path, &nsis_installer_path)?; From c2b8f4783217d4a8a9e22b2d333727f4de2c57b0 Mon Sep 17 00:00:00 2001 From: Onyeka Obi Date: Sun, 24 May 2026 05:28:35 -0700 Subject: [PATCH 15/15] enhance: include permission identifier in ACL error messages (#15373) --- .changes/acl-identifier-error-context.md | 9 +++++++++ crates/tauri-utils/src/acl/identifier.rs | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .changes/acl-identifier-error-context.md diff --git a/.changes/acl-identifier-error-context.md b/.changes/acl-identifier-error-context.md new file mode 100644 index 000000000000..0918e9266fcd --- /dev/null +++ b/.changes/acl-identifier-error-context.md @@ -0,0 +1,9 @@ +--- +"tauri-utils": "patch:enhance" +--- + +Improve diagnostics for invalid plugin and permission identifiers. + +The `Identifier` deserializer now wraps the inner error with the offending identifier string so the message reads `invalid plugin or permission identifier '': ...`, surfacing the bad entry without requiring a grep through the file. + +The previous parse failure (`failed to parse JSON: identifiers can only include lowercase ASCII, hyphens which are not leading or trailing, and a single colon if using a prefix at line 16 column 23`) now reads `failed to parse JSON: invalid plugin or permission identifier 'sqlite_proxy:allow-foo': identifiers can only include lowercase ASCII, hyphens which are not leading or trailing, and a single colon if using a prefix at line 16 column 23`. diff --git a/crates/tauri-utils/src/acl/identifier.rs b/crates/tauri-utils/src/acl/identifier.rs index 7b9f90f2f4fd..72a7ec2f359c 100644 --- a/crates/tauri-utils/src/acl/identifier.rs +++ b/crates/tauri-utils/src/acl/identifier.rs @@ -216,7 +216,12 @@ impl<'de> Deserialize<'de> for Identifier { where D: Deserializer<'de>, { - Self::try_from(String::deserialize(deserializer)?).map_err(serde::de::Error::custom) + let raw = String::deserialize(deserializer)?; + Self::try_from(raw.clone()).map_err(|e| { + serde::de::Error::custom(format!( + "invalid plugin or permission identifier '{raw}': {e}" + )) + }) } }