diff --git a/.changes/nsis-slow-resources-installation.md b/.changes/nsis-slow-resources-installation.md new file mode 100644 index 000000000..486227050 --- /dev/null +++ b/.changes/nsis-slow-resources-installation.md @@ -0,0 +1,7 @@ +--- +"@tauri-apps/cli": patch:bug +"tauri-cli": patch:bug +"tauri-bundler": patch:bug +--- + +Fixes an issue in the NSIS installer which caused the installation to take much longer than expected when many `resources` were added to the bundle. diff --git a/tooling/bundler/src/bundle/windows/nsis.rs b/tooling/bundler/src/bundle/windows/nsis.rs index b0711b31e..afa148ddb 100644 --- a/tooling/bundler/src/bundle/windows/nsis.rs +++ b/tooling/bundler/src/bundle/windows/nsis.rs @@ -290,23 +290,27 @@ fn build_nsis_app_installer( .iter() .find(|bin| bin.main()) .ok_or_else(|| anyhow::anyhow!("Failed to get main binary"))?; + let main_binary_path = settings.binary_path(main_binary).with_extension("exe"); data.insert( "main_binary_name", to_json(main_binary.name().replace(".exe", "")), ); - data.insert( - "main_binary_path", - to_json(settings.binary_path(main_binary).with_extension("exe")), - ); + data.insert("main_binary_path", to_json(&main_binary_path)); let out_file = "nsis-output.exe"; data.insert("out_file", to_json(out_file)); let resources = generate_resource_data(settings)?; - data.insert("resources", to_json(resources)); + let resources_dirs = + std::collections::HashSet::::from_iter(resources.values().map(|r| r.0.to_owned())); + data.insert("resources_dirs", to_json(resources_dirs)); + data.insert("resources", to_json(&resources)); let binaries = generate_binaries_data(settings)?; - data.insert("binaries", to_json(binaries)); + data.insert("binaries", to_json(&binaries)); + + let estimated_size = generate_estimated_size(&main_binary_path, &binaries, &resources)?; + data.insert("estimated_size", to_json(estimated_size)); let silent_webview2_install = if let WebviewInstallMode::DownloadBootstrapper { silent } | WebviewInstallMode::EmbedBootstrapper { silent } @@ -552,6 +556,24 @@ fn generate_binaries_data(settings: &Settings) -> crate::Result { Ok(binaries) } +fn generate_estimated_size( + main: &Path, + binaries: &BinariesMap, + resources: &ResourcesMap, +) -> crate::Result { + use std::fs::metadata; + + let mut size = metadata(main)?.len(); + + for k in binaries.keys().chain(resources.keys()) { + size += metadata(k)?.len(); + } + + size /= 1000; + + Ok(format!("{size:#08x}")) +} + fn get_lang_data( lang: &str, custom_lang_files: Option<&HashMap>, diff --git a/tooling/bundler/src/bundle/windows/templates/installer.nsi b/tooling/bundler/src/bundle/windows/templates/installer.nsi index 45e63acc0..d19bce14e 100644 --- a/tooling/bundler/src/bundle/windows/templates/installer.nsi +++ b/tooling/bundler/src/bundle/windows/templates/installer.nsi @@ -40,6 +40,7 @@ ${StrLoc} !define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}" !define MANUPRODUCTKEY "Software\${MANUFACTURER}\${PRODUCTNAME}" !define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}" +!define ESTIMATEDSIZE "{{estimated_size}}" Name "${PRODUCTNAME}" BrandingText "${COPYRIGHT}" @@ -522,31 +523,26 @@ SectionEnd app_check_done: !macroend -Var AppSize Section Install SetOutPath $INSTDIR - StrCpy $AppSize 0 !insertmacro CheckIfAppIsRunning ; Copy main executable File "${MAINBINARYSRCPATH}" - ${GetSize} "$INSTDIR" "/M=${MAINBINARYNAME}.exe /S=0B" $0 $1 $2 - IntOp $AppSize $AppSize + $0 ; Copy resources + {{#each resources_dirs}} + ; `\\` is not a typo. + CreateDirectory "$INSTDIR\\{{this}}" + {{/each}} {{#each resources}} - CreateDirectory "$INSTDIR\\{{this.[0]}}" File /a "/oname={{this.[1]}}" "{{@key}}" - ${GetSize} "$INSTDIR" "/M={{this.[1]}} /S=0B" $0 $1 $2 - IntOp $AppSize $AppSize + $0 {{/each}} ; Copy external binaries {{#each binaries}} File /a "/oname={{this}}" "{{@key}}" - ${GetSize} "$INSTDIR" "/M={{this}} /S=0B" $0 $1 $2 - IntOp $AppSize $AppSize + $0 {{/each}} ; Create uninstaller @@ -570,9 +566,7 @@ Section Install WriteRegStr SHCTX "${UNINSTKEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" WriteRegDWORD SHCTX "${UNINSTKEY}" "NoModify" "1" WriteRegDWORD SHCTX "${UNINSTKEY}" "NoRepair" "1" - IntOp $AppSize $AppSize / 1000 - IntFmt $AppSize "0x%08X" $AppSize - WriteRegDWORD SHCTX "${UNINSTKEY}" "EstimatedSize" "$AppSize" + WriteRegDWORD SHCTX "${UNINSTKEY}" "EstimatedSize" "${ESTIMATEDSIZE}" ; Create start menu shortcut (GUI) !insertmacro MUI_STARTMENU_WRITE_BEGIN Application