fix(nextjs): kill Next.js server when parent process exits

This commit is contained in:
Jack Hsu 2023-05-24 09:44:13 -04:00 committed by Victor Savkin
parent a29afe98b2
commit 1fd7836a81
3 changed files with 22 additions and 23 deletions

View File

@ -50,7 +50,7 @@ export default async function buildExecutor(
const { experimentalAppOnly, profile, debug } = options; const { experimentalAppOnly, profile, debug } = options;
const args = createCliOptions({ experimentalAppOnly, profile, debug }); const args = createCliOptions({ experimentalAppOnly, profile, debug });
const command = `npx next build ${args}`; const command = `npx next build ${args.join(' ')}`;
const execSyncOptions: ExecSyncOptions = { const execSyncOptions: ExecSyncOptions = {
stdio: 'inherit', stdio: 'inherit',
encoding: 'utf-8', encoding: 'utf-8',

View File

@ -12,7 +12,7 @@ import {
NextBuildBuilderOptions, NextBuildBuilderOptions,
NextServeBuilderOptions, NextServeBuilderOptions,
} from '../../utils/types'; } from '../../utils/types';
import { spawn } from 'child_process'; import { fork } from 'child_process';
import customServer from './custom-server.impl'; import customServer from './custom-server.impl';
import { createCliOptions } from '../../utils/create-cli-options'; import { createCliOptions } from '../../utils/create-cli-options';
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable'; import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
@ -49,13 +49,13 @@ export default async function* serveExecutor(
const mode = options.dev ? 'dev' : 'start'; const mode = options.dev ? 'dev' : 'start';
const turbo = options.turbo && options.dev ? '--turbo' : ''; const turbo = options.turbo && options.dev ? '--turbo' : '';
const command = `npx next ${mode} ${args} ${turbo}`; const nextBin = require.resolve('next/dist/bin/next');
yield* createAsyncIterable<{ success: boolean; baseUrl: string }>( yield* createAsyncIterable<{ success: boolean; baseUrl: string }>(
async ({ done, next, error }) => { async ({ done, next, error }) => {
const server = spawn(command, { const server = fork(nextBin, [mode, ...args, turbo], {
cwd: options.dev ? root : nextDir, cwd: options.dev ? root : nextDir,
stdio: 'inherit', stdio: 'inherit',
shell: true,
}); });
server.once('exit', (code) => { server.once('exit', (code) => {
@ -66,15 +66,15 @@ export default async function* serveExecutor(
} }
}); });
process.on('exit', async (code) => { const killServer = () => {
if (code === 128 + 2) { if (server.connected) {
server.kill('SIGINT');
} else if (code === 128 + 1) {
server.kill('SIGHUP');
} else {
server.kill('SIGTERM'); server.kill('SIGTERM');
} }
}); };
process.on('exit', () => killServer());
process.on('SIGINT', () => killServer());
process.on('SIGTERM', () => killServer());
process.on('SIGHUP', () => killServer());
await waitForPortOpen(port); await waitForPortOpen(port);

View File

@ -1,12 +1,11 @@
export function createCliOptions(obj: { [key: string]: any }): string { export function createCliOptions(
return Object.entries(obj) obj: Record<string, string | number | boolean>
.reduce((arr, [key, value]) => { ): string[] {
if (value !== undefined) { return Object.entries(obj).reduce((arr, [key, value]) => {
const kebabCase = key.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()); if (value !== undefined) {
return `${arr}--${kebabCase}=${value} `; const kebabCase = key.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase());
} else { arr.push(`--${kebabCase}=${value}`);
return arr; }
} return arr;
}, '') }, []);
.trim();
} }