fix: 替换 execSync 为异步 runAsync 避免打包时主进程阻塞白屏

This commit is contained in:
gmh01
2026-07-23 20:53:11 +08:00
parent 90d3404cd8
commit 482a79f1c7
2 changed files with 42 additions and 15 deletions

View File

@@ -1,16 +1,37 @@
const fs = require('fs')
const path = require('path')
const { execSync, spawn } = require('child_process')
const { exec, spawn } = require('child_process')
const { getConfigPath, getSrcDir } = require('./project')
let isCancelled = false
let buildingProcess = null
function cancelPack() {
isCancelled = true
if (buildingProcess) {
try { buildingProcess.kill() } catch (e) {}
buildingProcess = null
}
}
function runAsync(cmd, args, options) {
return new Promise((resolve, reject) => {
const child = spawn(cmd, args, { ...options, shell: true, stdio: ['pipe', 'pipe', 'pipe'] })
let stdout = ''
let stderr = ''
child.stdout.on('data', (d) => { stdout += d.toString() })
child.stderr.on('data', (d) => { stderr += d.toString() })
child.on('error', reject)
child.on('close', (code) => {
if (code === 0) resolve(stdout)
else reject(new Error(stderr || stdout || `进程退出码 ${code}`))
})
})
}
async function startPack(projectPath, outputPath, onProgress) {
isCancelled = false
buildingProcess = null
const config = JSON.parse(fs.readFileSync(getConfigPath(projectPath), 'utf-8'))
const srcDir = getSrcDir(projectPath)
const tempDir = path.join(projectPath, '.web2app', 'temp-build')
@@ -91,17 +112,14 @@ async function startPack(projectPath, outputPath, onProgress) {
fs.writeFileSync(templatePackagePath, JSON.stringify(templatePackage, null, 2))
if (isCancelled) return { success: false, cancelled: true }
onProgress({ stage: 'install', message: '安装依赖 (首次较慢)...', percent: 50 })
onProgress({ stage: 'install', message: '正在安装依赖...', percent: 45 })
try {
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
execSync(`${npmCmd} install --production`, {
cwd: tempDir,
stdio: 'pipe',
timeout: 300000
})
onProgress({ stage: 'install', message: '正在安装依赖 (首次可能需要几分钟)...', percent: 50 })
await runAsync(npmCmd, ['install', '--production'], { cwd: tempDir, timeout: 300000 })
} catch (err) {
onProgress({ stage: 'install', message: `依赖安装失败: ${err.message}`, percent: 50 })
onProgress({ stage: 'error', message: `依赖安装失败: ${err.message}`, percent: 0 })
return { success: false, error: err.message }
}
@@ -112,7 +130,7 @@ async function startPack(projectPath, outputPath, onProgress) {
const builderPath = path.join(tempDir, 'node_modules', '.bin', 'electron-builder')
const builderCmd = process.platform === 'win32' ? `${builderPath}.cmd` : builderPath
const builderProcess = spawn(builderCmd, ['--config', templatePackagePath], {
buildingProcess = spawn(builderCmd, ['--config', templatePackagePath], {
cwd: tempDir,
shell: true,
stdio: ['pipe', 'pipe', 'pipe']
@@ -120,7 +138,7 @@ async function startPack(projectPath, outputPath, onProgress) {
let buildOutput = ''
builderProcess.stdout.on('data', (data) => {
buildingProcess.stdout.on('data', (data) => {
buildOutput += data.toString()
const msg = data.toString()
@@ -128,16 +146,24 @@ async function startPack(projectPath, outputPath, onProgress) {
onProgress({ stage: 'build', message: '正在打包...', percent: 75 })
} else if (msg.includes('signing')) {
onProgress({ stage: 'sign', message: '正在签名...', percent: 85 })
} else if (msg.includes('downloading')) {
onProgress({ stage: 'download', message: msg.trim(), percent: 55 })
} else if (msg.includes('building')) {
onProgress({ stage: 'build', message: msg.trim(), percent: 70 })
} else {
onProgress({ stage: 'build', message: msg.trim(), percent: 75 })
const line = msg.trim()
if (line) {
onProgress({ stage: 'build', message: line, percent: 65 })
}
}
})
builderProcess.stderr.on('data', (data) => {
buildingProcess.stderr.on('data', (data) => {
buildOutput += data.toString()
})
builderProcess.on('close', (code) => {
buildingProcess.on('close', (code) => {
buildingProcess = null
if (isCancelled) {
resolve({ success: false, cancelled: true })
return
@@ -173,7 +199,8 @@ async function startPack(projectPath, outputPath, onProgress) {
resolve({ success: true, outputPath: installerPath })
})
builderProcess.on('error', (err) => {
buildingProcess.on('error', (err) => {
buildingProcess = null
resolve({ success: false, error: err.message })
})
})