refactor: use pipe stdio for spawn Electron bytecode compliler and append stderr error

This commit is contained in:
alex8088 2026-10-01 22:44:18 +08:00
parent 395f0dae0c
commit 4c4bdf5248

View File

@ -34,6 +34,7 @@ export class ElectronCompiler {
private starting?: Promise<void> private starting?: Promise<void>
private stopping?: Promise<void> private stopping?: Promise<void>
private ready = false private ready = false
private stderr = ''
constructor(readonly options: ElectronCompilerOptions) { constructor(readonly options: ElectronCompilerOptions) {
for (const timeout of [options.timeout, options.shutdownTimeout]) { for (const timeout of [options.timeout, options.shutdownTimeout]) {
@ -57,12 +58,19 @@ export class ElectronCompiler {
private async initialize(): Promise<void> { private async initialize(): Promise<void> {
const env: NodeJS.ProcessEnv = { ...process.env, ...this.options.env, ELECTRON_VITE_RPC: 'true' } const env: NodeJS.ProcessEnv = { ...process.env, ...this.options.env, ELECTRON_VITE_RPC: 'true' }
delete env.ELECTRON_RUN_AS_NODE delete env.ELECTRON_RUN_AS_NODE
this.stderr = ''
const ps = spawn(this.options.path, this.options.args, { const ps = spawn(this.options.path, this.options.args, {
stdio: ['ignore', 'inherit', 'inherit', 'ipc'], stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
windowsHide: true, windowsHide: true,
env env
}) })
this.ps = ps this.ps = ps
if (ps.stderr) {
ps.stderr.setEncoding('utf8')
ps.stderr.on('data', (chunk: string) => {
if (this.ps === ps) this.stderr = (this.stderr + chunk).slice(-64 * 1024)
})
}
ps.on('message', (message: ElectronResponse) => { ps.on('message', (message: ElectronResponse) => {
if (this.ps !== ps || !message || message.type !== 'response') return if (this.ps !== ps || !message || message.type !== 'response') return
const pending = this.rpcMap.get(message.invocationId) const pending = this.rpcMap.get(message.invocationId)
@ -120,7 +128,7 @@ export class ElectronCompiler {
if (!pending) return if (!pending) return
clearTimeout(pending.timer) clearTimeout(pending.timer)
this.rpcMap.delete(invocationId) this.rpcMap.delete(invocationId)
reject(error) reject(this.withStderr(error))
} }
const timer = setTimeout(() => fail(new Error('Electron RPC timed out: ' + cmd)), this.options.timeout ?? 30000) const timer = setTimeout(() => fail(new Error('Electron RPC timed out: ' + cmd)), this.options.timeout ?? 30000)
this.rpcMap.set(invocationId, { resolve, reject, timer }) this.rpcMap.set(invocationId, { resolve, reject, timer })
@ -136,6 +144,7 @@ export class ElectronCompiler {
private rejectPending(error: Error): void { private rejectPending(error: Error): void {
this.ready = false this.ready = false
if (this.rpcMap.size) this.withStderr(error)
for (const pending of this.rpcMap.values()) { for (const pending of this.rpcMap.values()) {
clearTimeout(pending.timer) clearTimeout(pending.timer)
pending.reject(error) pending.reject(error)
@ -143,6 +152,16 @@ export class ElectronCompiler {
this.rpcMap.clear() this.rpcMap.clear()
} }
private withStderr(error: Error): Error {
const stderr = this.stderr.trim()
if (stderr) {
const stack = error.stack
error.message += '\n' + stderr
if (stack) error.stack = stack + '\n' + stderr
}
return error
}
stop(): Promise<void> { stop(): Promise<void> {
if (this.stopping) return this.stopping if (this.stopping) return this.stopping
this.rejectPending(new Error('ElectronCompiler stopped')) this.rejectPending(new Error('ElectronCompiler stopped'))