fix(dev): improve Electron process signal handling

This commit is contained in:
alex8088 2026-09-29 23:23:03 +08:00
parent d8e7702dc5
commit 55239df0ee

View File

@ -170,32 +170,31 @@ export function startElectron(root: string | undefined): ChildProcess {
// successful exit. Map a signal death to a non-zero status instead. // successful exit. Map a signal death to a non-zero status instead.
ps.on('close', (code, signal) => process.exit(code ?? (signal ? 1 : 0))) ps.on('close', (code, signal) => process.exit(code ?? (signal ? 1 : 0)))
forwardTerminationSignals(ps) setupElectronSignalHandlers(ps)
return ps return ps
} }
let signalHandlersInstalled = false let electronPs: ChildProcess | undefined
let currentElectronPs: ChildProcess | undefined let signalHandlersRegistered = false
// Forward termination signals to the Electron child, matching electron's own function setupElectronSignalHandlers(child: ChildProcess): void {
// CLI wrapper (node_modules/electron/cli.js). Without this, Ctrl-C kills the electronPs = child
// parent immediately and the Electron child can get stuck on macOS when a
// before-quit handler calls preventDefault then later app.quit(). See #899. if (signalHandlersRegistered) return
function forwardTerminationSignals(ps: ChildProcess): void {
currentElectronPs = ps const signals: NodeJS.Signals[] =
if (signalHandlersInstalled) return process.platform === 'win32' ? ['SIGINT', 'SIGTERM'] : ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGUSR2']
signalHandlersInstalled = true
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP'] as const) { for (const signal of signals) {
process.on(signal, () => { process.on(signal, () => {
const target = currentElectronPs const child = electronPs
if (target && target.exitCode === null && !target.killed) { if (!child?.pid || child.exitCode !== null || child.signalCode !== null) return
try {
target.kill(signal) // A previously sent signal does not mean the child has exited.
} catch { child.kill(signal)
// already gone
}
}
}) })
} }
signalHandlersRegistered = true
} }