From 6b6376d45f932696596677356d7d8ac182f1c4e6 Mon Sep 17 00:00:00 2001 From: Desuuuu Date: Thu, 25 Oct 2018 15:59:43 +0000 Subject: [PATCH] Fix: IPC-related issue on non-Windows platforms (#119) * Use SIGTERM instead of IPC on non-Windows platforms * Refactor serve tests for child exit * [skip ci] formatting(tests) This makes it so the IPC graceful exit is only used on non-windows platforms because of electron/electron/issues/14821 --- __tests__/commands.spec.js | 30 ++++++++++++++++++++++------ generator/template/src/background.js | 14 +++++++++---- index.js | 17 ++++++++++++---- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/__tests__/commands.spec.js b/__tests__/commands.spec.js index 7784b32a..47c2c362 100644 --- a/__tests__/commands.spec.js +++ b/__tests__/commands.spec.js @@ -317,6 +317,7 @@ describe('electron:build', () => { describe('electron:serve', () => { process.env.NODE_ENV = 'development' + const isWin = process.platform === 'win32' test('typescript is disabled when set in options', async () => { await runCommand('electron:serve', { @@ -466,6 +467,7 @@ describe('electron:serve', () => { expect(fs.watchFile.mock.calls[0][0]).toBe('projectPath/customBackground') // Child has not yet been killed or unwatched expect(mockExeca.send).not.toBeCalled() + expect(mockExeca.kill).not.toBeCalled() expect(mockExeca.removeAllListeners).not.toBeCalled() // Main process was bundled and Electron was launched initially expect(webpack).toHaveBeenCalledTimes(1) @@ -475,8 +477,13 @@ describe('electron:serve', () => { watchCb() childEvents.exit() // Electron was killed and listeners removed - expect(mockExeca.send).toHaveBeenCalledTimes(1) - expect(mockExeca.send).toHaveBeenCalledWith('graceful-exit') + if (isWin) { + expect(mockExeca.send).toHaveBeenCalledTimes(1) + expect(mockExeca.send).toHaveBeenCalledWith('graceful-exit') + } else { + expect(mockExeca.kill).toHaveBeenCalledTimes(1) + expect(mockExeca.kill).toHaveBeenCalledWith('SIGTERM') + } // Process did not exit on Electron close expect(process.exit).not.toBeCalled() // Main process file was recompiled @@ -509,6 +516,7 @@ describe('electron:serve', () => { expect(fs.watchFile.mock.calls[1][0]).toBe('projectPath/listFile') // Child has not yet been killed or unwatched expect(mockExeca.send).not.toBeCalled() + expect(mockExeca.kill).not.toBeCalled() expect(mockExeca.removeAllListeners).not.toBeCalled() // Main process was bundled and Electron was launched initially expect(webpack).toHaveBeenCalledTimes(1) @@ -518,8 +526,13 @@ describe('electron:serve', () => { watchCb['projectPath/listFile']() childEvents.exit() // Electron was killed and listeners removed - expect(mockExeca.send).toHaveBeenCalledTimes(1) - expect(mockExeca.send).toHaveBeenCalledWith('graceful-exit') + if (isWin) { + expect(mockExeca.send).toHaveBeenCalledTimes(1) + expect(mockExeca.send).toHaveBeenCalledWith('graceful-exit') + } else { + expect(mockExeca.kill).toHaveBeenCalledTimes(1) + expect(mockExeca.kill).toHaveBeenCalledWith('SIGTERM') + } // Process did not exit on Electron close expect(process.exit).not.toBeCalled() // Main process file was recompiled @@ -531,8 +544,13 @@ describe('electron:serve', () => { watchCb['projectPath/customBackground']() childEvents.exit() // Electron was killed and listeners removed - expect(mockExeca.send).toHaveBeenCalledTimes(2) - expect(mockExeca.send).toHaveBeenCalledWith('graceful-exit') + if (isWin) { + expect(mockExeca.send).toHaveBeenCalledTimes(2) + expect(mockExeca.send).toHaveBeenCalledWith('graceful-exit') + } else { + expect(mockExeca.kill).toHaveBeenCalledTimes(2) + expect(mockExeca.kill).toHaveBeenCalledWith('SIGTERM') + } // Process did not exit on Electron close expect(process.exit).not.toBeCalled() // Main process file was recompiled diff --git a/generator/template/src/background.js b/generator/template/src/background.js index 178d2bf1..8d5f0be5 100644 --- a/generator/template/src/background.js +++ b/generator/template/src/background.js @@ -62,9 +62,15 @@ app.on('ready', async () => { // Exit cleanly on request from parent process in development mode. if (isDevelopment) { - process.on('message', data => { - if (data === 'graceful-exit') { + if (process.platform === 'win32') { + process.on('message', data => { + if (data === 'graceful-exit') { + app.quit() + } + }) + } else { + process.on('SIGTERM', () => { app.quit() - } - }) + }) + } } diff --git a/index.js b/index.js index 9af7d2ff..fd397485 100644 --- a/index.js +++ b/index.js @@ -273,12 +273,16 @@ module.exports = (api, options) => { } // Attempt to kill gracefully - child.send('graceful-exit') + if (process.platform === 'win32') { + child.send('graceful-exit') + } else { + child.kill('SIGTERM') + } - // Kill after 2 seconds if unsuccessful + // Kill unconditionally after 2 seconds if unsuccessful childExitTimeout = setTimeout(() => { if (child) { - child.kill() + child.kill('SIGKILL') } }, 2000) } @@ -360,6 +364,11 @@ module.exports = (api, options) => { // Disable Electron process auto restart childRestartOnExit = 0 + let stdioConfig = [null, null, null] + + // Use an IPC on Windows for graceful exit + if (process.platform === 'win32') stdioConfig.push('ipc') + child = execa( require('electron'), [ @@ -375,7 +384,7 @@ module.exports = (api, options) => { // Disable electron security warnings ELECTRON_DISABLE_SECURITY_WARNINGS: true }, - stdio: [null, null, null, 'ipc'] + stdio: stdioConfig } )