fix: 替换 execSync 为异步 runAsync 避免打包时主进程阻塞白屏
This commit is contained in:
@@ -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 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<div class="progress-bar" :style="{ width: progress.percent + '%' }"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="progress.percent > 0" class="progress-info">
|
||||
<div v-if="progress.stage" class="progress-info">
|
||||
<span class="progress-label">{{ stageLabel }}</span>
|
||||
<span class="progress-percent">{{ Math.round(progress.percent) }}%</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user