From 26540d30c991330fcbc82c501bdad88ae7f2d030 Mon Sep 17 00:00:00 2001 From: Brendan Dash Date: Mon, 4 Nov 2024 11:29:57 +0800 Subject: [PATCH] feat: wait next server is available --- lib/nextron-dev.ts | 159 +++++++++++++++++++++++---------------------- package.json | 1 + pnpm-lock.yaml | 12 +++- 3 files changed, 92 insertions(+), 80 deletions(-) diff --git a/lib/nextron-dev.ts b/lib/nextron-dev.ts index e9791ec7..98d7f236 100755 --- a/lib/nextron-dev.ts +++ b/lib/nextron-dev.ts @@ -4,6 +4,7 @@ import webpack from 'webpack' import * as logger from './logger' import { getNextronConfig } from './configs/getNextronConfig' import { config } from './configs/webpack.config.development' +import { waitForPort } from 'get-port-please' import type { ChildProcess } from 'child_process' const args = arg({ @@ -42,7 +43,7 @@ if (args['--inspect']) { const nextronConfig = getNextronConfig() const rendererPort = args['--renderer-port'] || 8888 -const startupDelay = nextronConfig.startupDelay || args['--startup-delay'] || 0 +const startupDelay = nextronConfig.startupDelay || args['--startup-delay'] || 10_000 let electronOptions = args['--electron-options'] || '' if (!electronOptions.includes('--remote-debugging-port')) { @@ -58,91 +59,93 @@ const execaOptions: execa.Options = { stdio: 'inherit', } -;(async () => { - let firstCompile = true - let watching: webpack.Watching - let mainProcess: ChildProcess - let rendererProcess: ChildProcess // eslint-disable-line prefer-const - - const startMainProcess = () => { - logger.info( - `Run main process: electron . ${rendererPort} ${electronOptions}` - ) - mainProcess = execa( - 'electron', - ['.', `${rendererPort}`, `${electronOptions}`], - { - detached: true, - ...execaOptions, - } - ) - mainProcess.unref() - } - - const startRendererProcess = () => { - logger.info( - `Run renderer process: next -p ${rendererPort} ${ - nextronConfig.rendererSrcDir || 'renderer' - }` - ) - const child = execa( - 'next', - ['-p', rendererPort, nextronConfig.rendererSrcDir || 'renderer'], - execaOptions - ) - child.on('close', () => { - process.exit(0) - }) - return child - } - - const killWholeProcess = () => { - if (watching) { - watching.close(() => {}) - } - if (mainProcess) { - mainProcess.kill() - } - if (rendererProcess) { - rendererProcess.kill() + ; (async () => { + let firstCompile = true + let watching: webpack.Watching + let mainProcess: ChildProcess + let rendererProcess: ChildProcess // eslint-disable-line prefer-const + + const startMainProcess = () => { + logger.info( + `Run main process: electron . ${rendererPort} ${electronOptions}` + ) + mainProcess = execa( + 'electron', + ['.', `${rendererPort}`, `${electronOptions}`], + { + detached: true, + ...execaOptions, + } + ) + mainProcess.unref() } - } - - process.on('SIGINT', killWholeProcess) - process.on('SIGTERM', killWholeProcess) - process.on('exit', killWholeProcess) - - rendererProcess = startRendererProcess() - // wait until renderer process is ready - await new Promise((resolve) => - setTimeout(() => resolve(), startupDelay) - ) + const startRendererProcess = () => { + logger.info( + `Run renderer process: next -p ${rendererPort} ${nextronConfig.rendererSrcDir || 'renderer' + }` + ) + const child = execa( + 'next', + ['-p', rendererPort, nextronConfig.rendererSrcDir || 'renderer'], + execaOptions + ) + child.on('close', () => { + process.exit(0) + }) + return child + } - // wait until main process is ready - await new Promise((resolve) => { - const compiler = webpack(config) - watching = compiler.watch({}, (error) => { - if (error) { - console.error(error.stack || error) + const killWholeProcess = () => { + if (watching) { + watching.close(() => { }) + } + if (mainProcess) { + mainProcess.kill() + } + if (rendererProcess) { + rendererProcess.kill() } + } - if (!args['--run-only']) { - if (!firstCompile && mainProcess) { - mainProcess.kill() + process.on('SIGINT', killWholeProcess) + process.on('SIGTERM', killWholeProcess) + process.on('exit', killWholeProcess) + + rendererProcess = startRendererProcess() + + // wait until renderer process is ready + await waitForPort(rendererPort, { delay: 500, retries: startupDelay / 500 }) + .catch(() => { + logger.error(`Failed to start renderer process with port ${rendererPort} in ${startupDelay}ms`) + killWholeProcess() + process.exit(1) + }) + + // wait until main process is ready + await new Promise((resolve) => { + const compiler = webpack(config) + watching = compiler.watch({}, (error) => { + if (error) { + console.error(error.stack || error) } - startMainProcess() - if (firstCompile) { - firstCompile = false + if (!args['--run-only']) { + if (!firstCompile && mainProcess) { + mainProcess.kill() + } + startMainProcess() + + if (firstCompile) { + firstCompile = false + } } - } - resolve() + resolve() + }) }) - }) - if (args['--run-only']) { - startMainProcess() - } -})() + if (args['--run-only']) { + startMainProcess() + } + })() diff --git a/package.json b/package.json index 242b3fa5..b2fbf611 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "chalk": "4.1.2", "execa": "5.1.1", "fs-extra": "11.2.0", + "get-port-please": "^3.1.2", "terser-webpack-plugin": "5.3.10", "tsconfig-paths-webpack-plugin": "4.1.0", "webpack": "5.92.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index effb0a82..a6a7601f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: fs-extra: specifier: 11.2.0 version: 11.2.0 + get-port-please: + specifier: ^3.1.2 + version: 3.1.2 terser-webpack-plugin: specifier: 5.3.10 version: 5.3.10(webpack@5.92.0) @@ -1797,6 +1800,9 @@ packages: get-intrinsic@1.2.1: resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-port-please@3.1.2: + resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} @@ -4705,7 +4711,7 @@ snapshots: debug: 4.3.4 enhanced-resolve: 5.17.0 eslint: 9.5.0 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.20.0(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.20.0(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@9.5.0))(eslint@9.5.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.20.0(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0) eslint-plugin-import: 2.28.1(@typescript-eslint/parser@7.13.0(eslint@9.5.0)(typescript@5.4.5))(eslint@9.5.0) fast-glob: 3.3.1 get-tsconfig: 4.7.3 @@ -4717,7 +4723,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.0(@typescript-eslint/parser@6.20.0(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.20.0(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.28.1)(eslint@9.5.0))(eslint@9.5.0): + eslint-module-utils@2.8.0(@typescript-eslint/parser@6.20.0(eslint@9.5.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.5.0): dependencies: debug: 3.2.7 optionalDependencies: @@ -5008,6 +5014,8 @@ snapshots: has-proto: 1.0.1 has-symbols: 1.0.3 + get-port-please@3.1.2: {} + get-stream@6.0.1: {} get-stream@8.0.1: {}