react-universally
Version:
A starter kit for universal react applications.
129 lines (110 loc) • 3.19 kB
JavaScript
import path from 'path';
import appRootDir from 'app-root-dir';
import { spawn } from 'child_process';
import { log } from '../utils';
class HotNodeServer {
constructor(name, compiler, clientCompiler) {
const compiledEntryFile = path.resolve(
appRootDir.get(),
compiler.options.output.path,
`${Object.keys(compiler.options.entry)[0]}.js`,
);
const startServer = () => {
if (this.server) {
this.server.kill();
this.server = null;
log({
title: name,
level: 'info',
message: 'Restarting server...',
});
}
const newServer = spawn('node', [compiledEntryFile]);
log({
title: name,
level: 'info',
message: 'Server running with latest changes.',
notify: true,
});
newServer.stdout.on('data', data => console.log(data.toString().trim()));
newServer.stderr.on('data', (data) => {
log({
title: name,
level: 'error',
message: 'Error in server execution, check the console for more info.',
});
console.error(data.toString().trim());
});
this.server = newServer;
};
// We want our node server bundles to only start after a successful client
// build. This avoids any issues with node server bundles depending on
// client bundle assets.
const waitForClientThenStartServer = () => {
if (this.serverCompiling) {
// A new server bundle is building, break this loop.
return;
}
if (this.clientCompiling) {
setTimeout(waitForClientThenStartServer, 50);
} else {
startServer();
}
};
clientCompiler.plugin('compile', () => {
this.clientCompiling = true;
});
clientCompiler.plugin('done', (stats) => {
if (!stats.hasErrors()) {
this.clientCompiling = false;
}
});
compiler.plugin('compile', () => {
this.serverCompiling = true;
log({
title: name,
level: 'info',
message: 'Building new bundle...',
});
});
compiler.plugin('done', (stats) => {
this.serverCompiling = false;
if (this.disposing) {
return;
}
try {
if (stats.hasErrors()) {
log({
title: name,
level: 'error',
message: 'Build failed, check the console for more information.',
notify: true,
});
console.log(stats.toString());
return;
}
waitForClientThenStartServer();
} catch (err) {
log({
title: name,
level: 'error',
message: 'Failed to start, please check the console for more information.',
notify: true,
});
console.error(err);
}
});
// Lets start the compiler.
this.watcher = compiler.watch(null, () => undefined);
}
dispose() {
this.disposing = true;
const stopWatcher = new Promise((resolve) => {
this.watcher.close(resolve);
});
return stopWatcher.then(() => {
if (this.server) this.server.kill();
});
}
}
export default HotNodeServer;