From 07afdd8eebed662eec3e322dbae0f5f3eca2cee2 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 13 Nov 2025 06:30:24 +0000 Subject: [PATCH] Fix Windows installation timeout with smart retry mechanism (#1071) Problem: - Windows users experiencing 10-minute timeout during first build - Network detection didn't help users with low latency but slow downloads - Native compilation and antivirus scanning make Windows builds slower Solution: 1. Increase timeout: Windows 15min (from 10min), other platforms 10min (from 5min) 2. Smart retry: Auto-retry with CN mirror if first attempt times out 3. Better UX: Show expected time (10-15min for Windows first build) 4. Documentation: Add Windows timeout troubleshooting to FAQ Technical changes: - BaseBuilder.ts: Implement try-catch with automatic mirror fallback - FAQ: Document the issue, causes, and solutions in both EN/CN - User-friendly messages for first-time setup expectations Fixes #1071 --- bin/builders/BaseBuilder.ts | 83 +++++++++++++++++++++++++++---------- dist/cli.js | 58 +++++++++++++++++++------- docs/faq.md | 48 +++++++++++++++++++++ docs/faq_CN.md | 48 +++++++++++++++++++++ 4 files changed, 200 insertions(+), 37 deletions(-) diff --git a/bin/builders/BaseBuilder.ts b/bin/builders/BaseBuilder.ts index 18d4d5e..9d4a135 100644 --- a/bin/builders/BaseBuilder.ts +++ b/bin/builders/BaseBuilder.ts @@ -34,7 +34,8 @@ export default abstract class BaseBuilder { } private getInstallTimeout(): number { - return process.platform === 'win32' ? 600000 : 300000; + // Windows needs more time due to native compilation and antivirus scanning + return process.platform === 'win32' ? 900000 : 600000; } private getBuildTimeout(): number { @@ -100,38 +101,74 @@ export default abstract class BaseBuilder { const projectConf = path.join(rustProjectDir, 'config.toml'); await fsExtra.ensureDir(rustProjectDir); - // 智能检测可用的包管理器 + // Detect available package manager const packageManager = await this.detectPackageManager(); - const registryOption = isChina - ? ' --registry=https://registry.npmmirror.com' - : ''; - // 根据包管理器类型设置依赖冲突解决选项 + const registryOption = ' --registry=https://registry.npmmirror.com'; const peerDepsOption = packageManager === 'npm' ? ' --legacy-peer-deps' : ''; const timeout = this.getInstallTimeout(); - const buildEnv = this.getBuildEnvironment(); - if (isChina) { + // Show helpful message for first-time users + if (!tauriTargetPathExists) { 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, - ); - } else { - await shellExec( - `cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, - timeout, - buildEnv, + process.platform === 'win32' + ? '✺ First-time setup may take 10-15 minutes on Windows (compiling dependencies)...' + : '✺ First-time setup may take 5-10 minutes (installing dependencies)...', ); } - spinner.succeed(chalk.green('Package installed!')); + + let usedMirror = isChina; + + try { + if (isChina) { + 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, + ); + } else { + await shellExec( + `cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, + timeout, + buildEnv, + ); + } + spinner.succeed(chalk.green('Package installed!')); + } catch (error: any) { + // If installation times out and we haven't tried the mirror yet, retry with mirror + if (error.message?.includes('timed out') && !usedMirror) { + spinner.fail(chalk.yellow('Installation timed out, retrying with CN mirror...')); + logger.info('✺ Retrying installation with CN mirror for better speed...'); + + const retrySpinner = getSpinner('Retrying installation...'); + usedMirror = true; + + try { + const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml'); + await fsExtra.copy(projectCnConf, projectConf); + await shellExec( + `cd "${npmDirectory}" && ${packageManager} install${registryOption}${peerDepsOption}`, + timeout, + buildEnv, + ); + retrySpinner.succeed(chalk.green('Package installed with CN mirror!')); + } catch (retryError) { + retrySpinner.fail(chalk.red('Installation failed')); + throw retryError; + } + } else { + spinner.fail(chalk.red('Installation failed')); + throw error; + } + } + if (!tauriTargetPathExists) { logger.warn( '✼ The first packaging may be slow, please be patient and wait, it will be faster afterwards.', diff --git a/dist/cli.js b/dist/cli.js index 8a70f86..61f1597 100755 --- a/dist/cli.js +++ b/dist/cli.js @@ -730,7 +730,8 @@ class BaseBuilder { : undefined; } getInstallTimeout() { - return process.platform === 'win32' ? 600000 : 300000; + // Windows needs more time due to native compilation and antivirus scanning + return process.platform === 'win32' ? 900000 : 600000; } getBuildTimeout() { return 900000; @@ -786,25 +787,54 @@ class BaseBuilder { const rustProjectDir = path.join(tauriSrcPath, '.cargo'); const projectConf = path.join(rustProjectDir, 'config.toml'); await fsExtra.ensureDir(rustProjectDir); - // 智能检测可用的包管理器 + // Detect available package manager const packageManager = await this.detectPackageManager(); - const registryOption = isChina - ? ' --registry=https://registry.npmmirror.com' - : ''; - // 根据包管理器类型设置依赖冲突解决选项 + const registryOption = ' --registry=https://registry.npmmirror.com'; const peerDepsOption = packageManager === 'npm' ? ' --legacy-peer-deps' : ''; const timeout = this.getInstallTimeout(); const buildEnv = this.getBuildEnvironment(); - if (isChina) { - 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); + // Show helpful message for first-time users + if (!tauriTargetPathExists) { + logger.info(process.platform === 'win32' + ? '✺ First-time setup may take 10-15 minutes on Windows (compiling dependencies)...' + : '✺ First-time setup may take 5-10 minutes (installing dependencies)...'); } - else { - await shellExec(`cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, timeout, buildEnv); + let usedMirror = isChina; + try { + if (isChina) { + 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); + } + else { + await shellExec(`cd "${npmDirectory}" && ${packageManager} install${peerDepsOption}`, timeout, buildEnv); + } + spinner.succeed(chalk.green('Package installed!')); + } + catch (error) { + // If installation times out and we haven't tried the mirror yet, retry with mirror + if (error.message?.includes('timed out') && !usedMirror) { + spinner.fail(chalk.yellow('Installation timed out, retrying with CN mirror...')); + logger.info('✺ Retrying installation with CN mirror for better speed...'); + const retrySpinner = getSpinner('Retrying installation...'); + usedMirror = true; + try { + const projectCnConf = path.join(tauriSrcPath, 'rust_proxy.toml'); + await fsExtra.copy(projectCnConf, projectConf); + await shellExec(`cd "${npmDirectory}" && ${packageManager} install${registryOption}${peerDepsOption}`, timeout, buildEnv); + retrySpinner.succeed(chalk.green('Package installed with CN mirror!')); + } + catch (retryError) { + retrySpinner.fail(chalk.red('Installation failed')); + throw retryError; + } + } + else { + spinner.fail(chalk.red('Installation failed')); + throw error; + } } - spinner.succeed(chalk.green('Package installed!')); if (!tauriTargetPathExists) { logger.warn('✼ The first packaging may be slow, please be patient and wait, it will be faster afterwards.'); } diff --git a/docs/faq.md b/docs/faq.md index 2c8cfb2..93b4069 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -6,6 +6,54 @@ Common issues and solutions when using Pake. ## Build Issues +### Windows: Installation Timeout During First Build + +**Problem:** +When building for the first time on Windows, you may encounter: + +```txt +Error: Command timed out after 900000ms: "cd ... && pnpm install" +``` + +**Why This Happens:** + +First-time installation on Windows can be slow due to: +- Native module compilation (requires Visual Studio Build Tools) +- Large dependency downloads (Tauri, Rust toolchain) +- Windows Defender real-time scanning +- Network connectivity issues + +**Solution 1: Automatic Retry (Built-in)** + +Pake CLI now automatically retries with CN mirror if the initial installation times out. Simply wait for the retry to complete. + +**Solution 2: Manual Installation** + +If automatic retry fails, manually install dependencies: + +```bash +# Navigate to pake-cli installation directory +cd %LOCALAPPDATA%\pnpm\global\5\.pnpm\pake-cli@VERSION\node_modules\pake-cli + +# Install with CN mirror +pnpm install --registry=https://registry.npmmirror.com + +# Then retry your build +pake https://github.com --name GitHub +``` + +**Solution 3: Improve Network Speed** + +- Use a stable network connection +- Temporarily disable antivirus software during installation +- Use a VPN or proxy if needed + +**Expected Time:** +- First installation: 10-15 minutes on Windows +- Subsequent builds: Much faster (dependencies cached) + +--- + ### Linux: AppImage Build Fails with "failed to run linuxdeploy" **Problem:** diff --git a/docs/faq_CN.md b/docs/faq_CN.md index d4feabc..fb0d7c4 100644 --- a/docs/faq_CN.md +++ b/docs/faq_CN.md @@ -6,6 +6,54 @@ ## 构建问题 +### Windows:首次构建时安装超时 + +**问题描述:** +在 Windows 上首次构建时,可能遇到: + +```txt +Error: Command timed out after 900000ms: "cd ... && pnpm install" +``` + +**原因分析:** + +Windows 首次安装可能较慢,原因包括: +- 本地模块编译(需要 Visual Studio Build Tools) +- 大量依赖下载(Tauri、Rust 工具链) +- Windows Defender 实时扫描 +- 网络连接问题 + +**解决方案 1:自动重试(内置)** + +Pake CLI 现在会在初次安装超时后自动使用国内镜像重试。只需等待重试完成即可。 + +**解决方案 2:手动安装依赖** + +如果自动重试失败,可手动安装依赖: + +```bash +# 进入 pake-cli 安装目录 +cd %LOCALAPPDATA%\pnpm\global\5\.pnpm\pake-cli@版本号\node_modules\pake-cli + +# 使用国内镜像安装 +pnpm install --registry=https://registry.npmmirror.com + +# 然后重新构建 +pake https://github.com --name GitHub +``` + +**解决方案 3:改善网络环境** + +- 使用稳定的网络连接 +- 安装过程中临时关闭杀毒软件 +- 必要时使用 VPN 或代理 + +**预期时间:** +- 首次安装:Windows 上需要 10-15 分钟 +- 后续构建:依赖已缓存,速度会快很多 + +--- + ### Linux:AppImage 构建失败,提示 "failed to run linuxdeploy" **问题描述:**