refactor: internalize server start

This commit is contained in:
cha0s 2022-12-03 10:47:16 -06:00
parent 5791c7a894
commit 3597583dc9
3 changed files with 113 additions and 40 deletions

View File

@ -1,7 +1,5 @@
import cluster from 'cluster';
import {join} from 'path'; import {join} from 'path';
import {require as R} from '@flecks/core/server';
import banner from '@neutrinojs/banner'; import banner from '@neutrinojs/banner';
const { const {
@ -58,29 +56,14 @@ export const hooks = {
url: undefined, url: undefined,
}), }),
'@flecks/core.webpack': (target, config) => { '@flecks/core.webpack': (target, config) => {
const StartServerWebpackPlugin = R('start-server-webpack-plugin'); const plugin = config.plugins.find(({pluginName}) => pluginName === 'StartServerPlugin');
const plugin = config.plugins.find((plugin) => plugin instanceof StartServerWebpackPlugin);
// Extremely hackish, c'est la vie. // Extremely hackish, c'est la vie.
if (plugin) { if (plugin) {
/* eslint-disable no-underscore-dangle */ const {exec} = plugin.options;
plugin._startServer = function _startServerHacked(callback) { plugin.options.exec = (compilation) => {
const execArgv = this._getArgs(); plugin.options.args = [compilation.assets[exec].existsAt];
const inspectPort = this._getInspectPort(execArgv); return join(FLECKS_CORE_ROOT, 'node_modules', '.bin', 'electron');
const clusterOptions = {
args: [this._entryPoint],
exec: join(FLECKS_CORE_ROOT, 'node_modules', '.bin', 'electron'),
execArgv,
};
if (inspectPort) {
clusterOptions.inspectPort = inspectPort;
}
cluster.setupMaster(clusterOptions);
cluster.on('online', (worker) => {
callback(worker);
});
cluster.fork();
}; };
/* eslint-enable no-underscore-dangle */
} }
}, },
'@flecks/electron/server.initialize': async (electron, flecks) => { '@flecks/electron/server.initialize': async (electron, flecks) => {

View File

@ -3,9 +3,9 @@ const {join} = require('path');
const {require: R} = require('@flecks/core/server'); const {require: R} = require('@flecks/core/server');
const banner = require('@neutrinojs/banner'); const banner = require('@neutrinojs/banner');
const clean = require('@neutrinojs/clean'); const clean = require('@neutrinojs/clean');
const startServer = require('@neutrinojs/start-server');
const runtime = require('./runtime'); const runtime = require('./runtime');
const startServer = require('./start');
const { const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),
@ -69,23 +69,13 @@ module.exports = async (flecks) => {
// Augment the application-starting configuration. // Augment the application-starting configuration.
const start = (neutrino) => { const start = (neutrino) => {
if (isStarting) { if (isStarting) {
neutrino.use(startServer({name: 'index.js'})); neutrino.use(startServer({
// Really dumb that I can't just pass these in. exec: 'index.js',
neutrino.config // Bail hard on unhandled rejections and report.
.plugin('start-server') nodeArgs: [...nodeArgs, '--unhandled-rejections=strict', '--trace-uncaught'],
.tap((args) => { // HMR.
const options = args[0]; signal: !!hot,
options.keyboard = false; }));
// HMR.
options.signal = !!hot;
// Node args.
options.nodeArgs.push(...nodeArgs);
// Bail hard on unhandled rejections and report.
options.nodeArgs.push('--unhandled-rejections=strict');
options.nodeArgs.push('--trace-uncaught');
return args;
});
} }
}; };

View File

@ -0,0 +1,100 @@
const cluster = require('cluster');
class StartServerPlugin {
pluginName = 'StartServerPlugin';
worker = null;
constructor(options = {}) {
this.options = 'string' === typeof options
? {name: options}
: {
args: [],
nodeArgs: [],
signal: false,
...options,
};
}
apply(compiler) {
const {options: {exec, signal}, pluginName} = this;
const logger = compiler.getInfrastructureLogger(pluginName);
compiler.hooks.afterEmit.tapAsync(pluginName, (compilation, callback) => {
if (this.worker && this.worker.isConnected()) {
if (signal) {
process.kill(this.worker.process.pid, true === signal ? 'SIGUSR2' : signal);
}
callback();
return;
}
let entryPoint;
if (!exec) {
entryPoint = compilation.assets[Object.keys(compilation.assets)[0]].existsAt;
}
else if (compilation.assets[exec]) {
entryPoint = compilation.assets[exec].existsAt;
}
else if ('string' === typeof exec) {
entryPoint = exec;
}
else {
entryPoint = exec(compilation);
}
this.startServer(
entryPoint,
callback,
);
});
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);
}
startServer(exec, callback) {
const {args, nodeArgs} = this.options;
const execArgv = nodeArgs.concat(process.execArgv);
const inspectPort = this.constructor.inspectPortFromExecArgv(execArgv);
cluster.setupPrimary({
exec,
execArgv,
args,
...(inspectPort && {inspectPort}),
});
cluster.on('online', () => callback());
this.worker = cluster.fork();
}
}
module.exports = ({
nodeArgs = [],
pluginId = 'start-server',
...pluginOptions
} = {}) => (
({config, options}) => {
config
.plugin(pluginId)
.use(
StartServerPlugin,
[{...pluginOptions, nodeArgs: nodeArgs.concat(options.debug ? ['--inspect'] : [])}],
);
}
);