flecks/packages/server/build/start.js

122 lines
3.4 KiB
JavaScript
Raw Normal View History

2022-12-03 10:47:16 -06:00
const cluster = require('cluster');
2023-11-30 21:41:42 -06:00
const {join} = require('path');
2022-12-03 10:47:16 -06:00
class StartServerPlugin {
pluginName = 'StartServerPlugin';
worker = null;
constructor(options = {}) {
2023-12-01 05:34:33 -06:00
this.options = {
args: [],
2024-01-20 03:40:20 -06:00
env: {},
2023-12-01 05:34:33 -06:00
killOnExit: true,
nodeArgs: [],
signal: false,
...('string' === typeof options ? {name: options} : options),
};
2024-02-06 12:31:47 -06:00
['exit', 'SIGINT', 'SIGTERM']
.forEach((event) => {
process.on(event, () => {
2024-02-07 10:15:07 -06:00
this.worker?.kill('exit' === event ? 'SIGKILL' : event);
2024-02-06 12:31:47 -06:00
});
});
2022-12-03 10:47:16 -06:00
}
apply(compiler) {
const {options: {exec, signal}, pluginName} = this;
const logger = compiler.getInfrastructureLogger(pluginName);
2024-02-05 17:08:26 -06:00
compiler.hooks.afterEmit.tapPromise(pluginName, async (compilation) => {
2022-12-03 10:47:16 -06:00
if (this.worker && this.worker.isConnected()) {
if (signal) {
2024-02-11 22:37:14 -06:00
process.kill(
this.worker.process.pid,
true === signal ? 'SIGUSR2' : signal,
);
2024-02-05 17:08:26 -06:00
return undefined;
2022-12-03 10:47:16 -06:00
}
2024-02-05 17:08:26 -06:00
const promise = new Promise((resolve) => {
this.worker.on('disconnect', resolve);
});
this.worker.disconnect();
await promise;
2022-12-03 10:47:16 -06:00
}
let entryPoint;
if (!exec) {
2023-11-30 21:41:42 -06:00
entryPoint = compilation.getPath(Object.keys(compilation.assets)[0]);
2022-12-03 10:47:16 -06:00
}
else if (compilation.assets[exec]) {
2023-11-30 21:41:42 -06:00
entryPoint = compilation.getPath(exec);
2022-12-03 10:47:16 -06:00
}
else if ('string' === typeof exec) {
entryPoint = exec;
}
else {
entryPoint = exec(compilation);
}
2024-02-05 17:08:26 -06:00
return this.startServer(join(compiler.options.output.path, entryPoint));
2022-12-03 10:47:16 -06:00
});
compiler.hooks.shouldEmit.tap(pluginName, (compilation) => {
const entryPoints = Object.keys(compilation.assets);
if ('string' === typeof exec) {
return true;
}
if (!exec && entryPoints.length > 1) {
logger.warn(`No entrypoint selected, defaulting to '${entryPoints[0]}'. Other entrypoints: '${entryPoints.slice(1).join("', '")}'`);
}
return true;
});
}
static inspectPortFromExecArgv(execArgv) {
const inspectArg = execArgv.find((arg) => arg.includes('--inspect'));
if (!inspectArg || !inspectArg.includes('=')) {
return undefined;
}
const [, hostPort] = inspectArg.split('=');
const port = hostPort.includes(':') ? hostPort.split(':')[1] : hostPort;
return parseInt(port, 10);
}
2024-02-05 17:08:26 -06:00
async startServer(exec) {
2024-01-20 03:40:20 -06:00
const {
args,
env,
killOnExit,
nodeArgs,
} = this.options;
2022-12-03 10:47:16 -06:00
const execArgv = nodeArgs.concat(process.execArgv);
const inspectPort = this.constructor.inspectPortFromExecArgv(execArgv);
cluster.setupPrimary({
exec,
execArgv,
args,
...(inspectPort && {inspectPort}),
});
2024-02-06 12:31:47 -06:00
this.worker = cluster.fork(env);
2024-02-11 21:03:06 -06:00
this.worker.on('exit', (code) => {
if (killOnExit) {
process.send({type: 'kill', payload: code});
process.exit(code);
}
});
2024-02-07 19:33:57 -06:00
this.worker.on('disconnect', () => {
if (this.worker.exitedAfterDisconnect) {
// eslint-disable-next-line no-console
console.error('[HMR] Restarting application...');
2024-02-11 21:03:06 -06:00
process.send({type: 'restart'});
2024-02-07 19:33:57 -06:00
}
});
2024-02-05 17:08:26 -06:00
return new Promise((resolve, reject) => {
this.worker.on('error', reject);
this.worker.on('online', resolve);
});
2022-12-03 10:47:16 -06:00
}
}
2023-11-30 21:41:42 -06:00
module.exports = (pluginOptions = {}) => (
new StartServerPlugin(pluginOptions)
2022-12-03 10:47:16 -06:00
);