fix: 替换 execSync 为异步 runAsync 避免打包时主进程阻塞白屏
This commit is contained in:
@@ -1,16 +1,37 @@
|
|||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { execSync, spawn } = require('child_process')
|
const { exec, spawn } = require('child_process')
|
||||||
const { getConfigPath, getSrcDir } = require('./project')
|
const { getConfigPath, getSrcDir } = require('./project')
|
||||||
|
|
||||||
let isCancelled = false
|
let isCancelled = false
|
||||||
|
let buildingProcess = null
|
||||||
|
|
||||||
function cancelPack() {
|
function cancelPack() {
|
||||||
isCancelled = true
|
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) {
|
async function startPack(projectPath, outputPath, onProgress) {
|
||||||
isCancelled = false
|
isCancelled = false
|
||||||
|
buildingProcess = null
|
||||||
const config = JSON.parse(fs.readFileSync(getConfigPath(projectPath), 'utf-8'))
|
const config = JSON.parse(fs.readFileSync(getConfigPath(projectPath), 'utf-8'))
|
||||||
const srcDir = getSrcDir(projectPath)
|
const srcDir = getSrcDir(projectPath)
|
||||||
const tempDir = path.join(projectPath, '.web2app', 'temp-build')
|
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))
|
fs.writeFileSync(templatePackagePath, JSON.stringify(templatePackage, null, 2))
|
||||||
|
|
||||||
if (isCancelled) return { success: false, cancelled: true }
|
if (isCancelled) return { success: false, cancelled: true }
|
||||||
onProgress({ stage: 'install', message: '安装依赖 (首次较慢)...', percent: 50 })
|
onProgress({ stage: 'install', message: '正在安装依赖...', percent: 45 })
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm'
|
||||||
execSync(`${npmCmd} install --production`, {
|
onProgress({ stage: 'install', message: '正在安装依赖 (首次可能需要几分钟)...', percent: 50 })
|
||||||
cwd: tempDir,
|
await runAsync(npmCmd, ['install', '--production'], { cwd: tempDir, timeout: 300000 })
|
||||||
stdio: 'pipe',
|
|
||||||
timeout: 300000
|
|
||||||
})
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
onProgress({ stage: 'install', message: `依赖安装失败: ${err.message}`, percent: 50 })
|
onProgress({ stage: 'error', message: `依赖安装失败: ${err.message}`, percent: 0 })
|
||||||
return { success: false, error: err.message }
|
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 builderPath = path.join(tempDir, 'node_modules', '.bin', 'electron-builder')
|
||||||
const builderCmd = process.platform === 'win32' ? `${builderPath}.cmd` : builderPath
|
const builderCmd = process.platform === 'win32' ? `${builderPath}.cmd` : builderPath
|
||||||
|
|
||||||
const builderProcess = spawn(builderCmd, ['--config', templatePackagePath], {
|
buildingProcess = spawn(builderCmd, ['--config', templatePackagePath], {
|
||||||
cwd: tempDir,
|
cwd: tempDir,
|
||||||
shell: true,
|
shell: true,
|
||||||
stdio: ['pipe', 'pipe', 'pipe']
|
stdio: ['pipe', 'pipe', 'pipe']
|
||||||
@@ -120,7 +138,7 @@ async function startPack(projectPath, outputPath, onProgress) {
|
|||||||
|
|
||||||
let buildOutput = ''
|
let buildOutput = ''
|
||||||
|
|
||||||
builderProcess.stdout.on('data', (data) => {
|
buildingProcess.stdout.on('data', (data) => {
|
||||||
buildOutput += data.toString()
|
buildOutput += data.toString()
|
||||||
const msg = data.toString()
|
const msg = data.toString()
|
||||||
|
|
||||||
@@ -128,16 +146,24 @@ async function startPack(projectPath, outputPath, onProgress) {
|
|||||||
onProgress({ stage: 'build', message: '正在打包...', percent: 75 })
|
onProgress({ stage: 'build', message: '正在打包...', percent: 75 })
|
||||||
} else if (msg.includes('signing')) {
|
} else if (msg.includes('signing')) {
|
||||||
onProgress({ stage: 'sign', message: '正在签名...', percent: 85 })
|
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 {
|
} 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()
|
buildOutput += data.toString()
|
||||||
})
|
})
|
||||||
|
|
||||||
builderProcess.on('close', (code) => {
|
buildingProcess.on('close', (code) => {
|
||||||
|
buildingProcess = null
|
||||||
if (isCancelled) {
|
if (isCancelled) {
|
||||||
resolve({ success: false, cancelled: true })
|
resolve({ success: false, cancelled: true })
|
||||||
return
|
return
|
||||||
@@ -173,7 +199,8 @@ async function startPack(projectPath, outputPath, onProgress) {
|
|||||||
resolve({ success: true, outputPath: installerPath })
|
resolve({ success: true, outputPath: installerPath })
|
||||||
})
|
})
|
||||||
|
|
||||||
builderProcess.on('error', (err) => {
|
buildingProcess.on('error', (err) => {
|
||||||
|
buildingProcess = null
|
||||||
resolve({ success: false, error: err.message })
|
resolve({ success: false, error: err.message })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<div class="progress-bar" :style="{ width: progress.percent + '%' }"></div>
|
<div class="progress-bar" :style="{ width: progress.percent + '%' }"></div>
|
||||||
</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-label">{{ stageLabel }}</span>
|
||||||
<span class="progress-percent">{{ Math.round(progress.percent) }}%</span>
|
<span class="progress-percent">{{ Math.round(progress.percent) }}%</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user