diff --git a/dist/cli.js b/dist/cli.js index e053014..3be1727 100755 --- a/dist/cli.js +++ b/dist/cli.js @@ -23,7 +23,7 @@ import sharp from 'sharp'; import * as psl from 'psl'; var name = "pake-cli"; -var version = "3.4.0"; +var version = "3.4.1"; var description = "๐Ÿคฑ๐Ÿป Turn any webpage into a desktop app with one command. ๐Ÿคฑ๐Ÿป ไธ€้”ฎๆ‰“ๅŒ…็ฝ‘้กต็”Ÿๆˆ่ฝป้‡ๆกŒ้ขๅบ”็”จใ€‚"; var engines = { node: ">=18.0.0" @@ -201,11 +201,13 @@ const IS_MAC = platform$1 === 'darwin'; const IS_WIN = platform$1 === 'win32'; const IS_LINUX = platform$1 === 'linux'; -async function shellExec(command, timeout = 300000, env, showOutput = false) { +async function shellExec(command, timeout = 300000, env) { try { const { exitCode } = await execa(command, { cwd: npmDirectory, - stdio: showOutput ? 'inherit' : ['inherit', 'pipe', 'inherit'], + // Use 'inherit' to show all output directly to user in real-time. + // This ensures linuxdeploy and other tool outputs are visible during builds. + stdio: 'inherit', shell: true, timeout, env: env ? { ...process.env, ...env } : process.env, @@ -219,15 +221,25 @@ async function shellExec(command, timeout = 300000, env, showOutput = false) { throw new Error(`Command timed out after ${timeout}ms: "${command}". Try increasing timeout or check network connectivity.`); } let errorMsg = `Error occurred while executing command "${command}". Exit code: ${exitCode}. Details: ${errorMessage}`; + // Provide helpful guidance for common Linux AppImage build failures + // caused by strip tool incompatibility with modern glibc (2.38+) if (process.platform === 'linux' && (errorMessage.includes('linuxdeploy') || errorMessage.includes('appimage') || errorMessage.includes('strip'))) { errorMsg += - '\n\nLinux AppImage build error. Try one of these solutions:\n' + - ' 1. Run with: NO_STRIP=true pake --targets appimage\n' + - ' 2. Use DEB format instead: pake --targets deb\n' + - ' 3. See detailed solutions: https://github.com/tw93/Pake/blob/main/docs/faq.md'; + '\n\nโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n' + + 'Linux AppImage Build Failed\n' + + 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”\n\n' + + 'Cause: Strip tool incompatibility with glibc 2.38+\n' + + ' (affects Debian Trixie, Arch Linux, and other modern distros)\n\n' + + 'Quick fix:\n' + + ' NO_STRIP=1 pake --targets appimage --debug\n\n' + + 'Alternatives:\n' + + ' โ€ข Use DEB format: pake --targets deb\n' + + ' โ€ข Update binutils: sudo apt install binutils (or pacman -S binutils)\n' + + ' โ€ข Detailed guide: https://github.com/tw93/Pake/blob/main/docs/faq.md\n' + + 'โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”'; } throw new Error(errorMsg); } @@ -351,7 +363,7 @@ async function installRust() { const rustInstallScriptForWindows = 'winget install --id Rustlang.Rustup'; const spinner = getSpinner('Downloading Rust...'); try { - await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac, 300000, undefined, true); + await shellExec(IS_WIN ? rustInstallScriptForWindows : rustInstallScriptForMac, 300000, undefined); spinner.succeed(chalk.green('โœ” Rust installed successfully!')); ensureRustEnv(); } @@ -448,13 +460,14 @@ async function mergeConfig(url, options, tauriConf) { await fsExtra.copy(sourcePath, destPath); } })); - const { width, height, fullscreen, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, } = options; + const { width, height, fullscreen, maximize, hideTitleBar, alwaysOnTop, appVersion, darkMode, disabledWebShortcuts, activationShortcut, userAgent, showSystemTray, systemTrayIcon, useLocalFile, identifier, name, resizable = true, inject, proxyUrl, installerLanguage, hideOnClose, incognito, title, wasm, enableDragDrop, multiInstance, startToTray, } = options; const { platform } = process; const platformHideOnClose = hideOnClose ?? platform === 'darwin'; const tauriConfWindowOptions = { width, height, fullscreen, + maximize, resizable, hide_title_bar: hideTitleBar, activation_shortcut: activationShortcut, @@ -466,6 +479,7 @@ async function mergeConfig(url, options, tauriConf) { title: title || null, enable_wasm: wasm, enable_drag_drop: enableDragDrop, + start_to_tray: startToTray && showSystemTray, }; Object.assign(tauriConf.pake.windows[0], { url, ...tauriConfWindowOptions }); tauriConf.productName = name; @@ -774,10 +788,10 @@ class BaseBuilder { logger.info(`โœบ Located in China, using ${packageManager}/rsProxy CN mirror.`); const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml'); await fsExtra.copy(projectCnConf, projectConf); - await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${peerDepsOption}`, timeout, buildEnv, this.options.debug); + await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${peerDepsOption}`, timeout, buildEnv); } else { - await shellExec(`cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, timeout, buildEnv, this.options.debug); + await shellExec(`cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, timeout, buildEnv); } spinner.succeed(chalk.green('Package installed!')); if (!tauriTargetPathExists) { @@ -806,7 +820,16 @@ class BaseBuilder { ...this.getBuildEnvironment(), ...(process.env.NO_STRIP && { NO_STRIP: process.env.NO_STRIP }), }; - await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand(packageManager)}`, this.getBuildTimeout(), buildEnv, this.options.debug); + // Warn users about potential AppImage build failures on modern Linux systems. + // The linuxdeploy tool bundled in Tauri uses an older strip tool that doesn't + // recognize the .relr.dyn section introduced in glibc 2.38+. + if (process.platform === 'linux' && this.options.targets === 'appimage') { + if (!buildEnv.NO_STRIP) { + logger.warn('โš  Building AppImage on Linux may fail due to strip incompatibility with glibc 2.38+'); + logger.warn('โš  If build fails, retry with: NO_STRIP=1 pake --targets appimage'); + } + } + await shellExec(`cd "${npmDirectory}" && ${this.getBuildCommand(packageManager)}`, this.getBuildTimeout(), buildEnv); // Copy app const fileName = this.getFileName(); const fileType = this.getFileType(target); @@ -865,6 +888,11 @@ class BaseBuilder { if (target) { fullCommand += ` --target ${target}`; } + // Enable verbose output in debug mode to help diagnose build issues. + // This provides detailed logs from Tauri CLI and bundler tools. + if (this.options.debug) { + fullCommand += ' --verbose'; + } return fullCommand; } /** @@ -1178,6 +1206,12 @@ class LinuxBuilder extends BaseBuilder { if (features.length > 0) { fullCommand += ` --features ${features.join(',')}`; } + // Enable verbose output for AppImage builds when debugging or PAKE_VERBOSE is set. + // AppImage builds often fail with minimal error messages from linuxdeploy, + // so verbose mode helps diagnose issues like strip failures and missing dependencies. + if (this.options.targets === 'appimage' && (this.options.debug || process.env.PAKE_VERBOSE)) { + fullCommand += ' --verbose'; + } return fullCommand; } getBasePath() { @@ -1227,6 +1261,7 @@ const DEFAULT_PAKE_OPTIONS = { height: 780, width: 1200, fullscreen: false, + maximize: false, hideTitleBar: false, alwaysOnTop: false, appVersion: '1.0.0', @@ -1249,6 +1284,7 @@ const DEFAULT_PAKE_OPTIONS = { enableDragDrop: false, keepBinary: false, multiInstance: false, + startToTray: false, }; async function checkUpdateTips() { @@ -1731,6 +1767,9 @@ program .addOption(new Option('--always-on-top', 'Always on the top level') .default(DEFAULT_PAKE_OPTIONS.alwaysOnTop) .hideHelp()) + .addOption(new Option('--maximize', 'Start window maximized') + .default(DEFAULT_PAKE_OPTIONS.maximize) + .hideHelp()) .addOption(new Option('--dark-mode', 'Force Mac app to use dark mode') .default(DEFAULT_PAKE_OPTIONS.darkMode) .hideHelp()) @@ -1774,6 +1813,9 @@ program .addOption(new Option('--multi-instance', 'Allow multiple app instances') .default(DEFAULT_PAKE_OPTIONS.multiInstance) .hideHelp()) + .addOption(new Option('--start-to-tray', 'Start app minimized to tray') + .default(DEFAULT_PAKE_OPTIONS.startToTray) + .hideHelp()) .addOption(new Option('--installer-language ', 'Installer language') .default(DEFAULT_PAKE_OPTIONS.installerLanguage) .hideHelp()) diff --git a/src-tauri/src/app/window.rs b/src-tauri/src/app/window.rs index 2aca7b9..9933b17 100644 --- a/src-tauri/src/app/window.rs +++ b/src-tauri/src/app/window.rs @@ -43,6 +43,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) -> .user_agent(user_agent) .resizable(window_config.resizable) .fullscreen(window_config.fullscreen) + .maximized(window_config.maximize) .inner_size(window_config.width, window_config.height) .always_on_top(window_config.always_on_top) .incognito(window_config.incognito); @@ -65,14 +66,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) -> .additional_browser_args("--enable-unsafe-webgpu"); } - if !config.proxy_url.is_empty() { - if let Ok(proxy_url) = Url::from_str(&config.proxy_url) { - window_builder = window_builder.proxy_url(proxy_url); - #[cfg(debug_assertions)] - println!("Proxy configured: {}", config.proxy_url); - } - } - + // Platform-specific configuration must be set before proxy on Windows/Linux #[cfg(target_os = "macos")] { let title_bar_style = if window_config.hide_title_bar { @@ -87,7 +81,7 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) -> } } - // Windows and Linux share the same configuration + // Windows and Linux: set data_directory before proxy_url #[cfg(not(target_os = "macos"))] { window_builder = window_builder @@ -96,5 +90,14 @@ pub fn set_window(app: &mut App, config: &PakeConfig, tauri_config: &Config) -> .theme(None); } + // Set proxy after platform-specific configs (required for Windows/Linux) + if !config.proxy_url.is_empty() { + if let Ok(proxy_url) = Url::from_str(&config.proxy_url) { + window_builder = window_builder.proxy_url(proxy_url); + #[cfg(debug_assertions)] + println!("Proxy configured: {}", config.proxy_url); + } + } + window_builder.build().expect("Failed to build window") }