latus/packages/http/src/http.js
2021-01-22 17:58:41 -06:00

119 lines
3.7 KiB
JavaScript

import {createReadStream} from 'fs';
import {createServer, ServerResponse} from 'http';
import {dirname, join} from 'path';
import {arrayFlatten, Latus} from '@latus/core';
import express from 'express';
import httpProxy from 'http-proxy';
import clientPlugins from './build/client-plugins';
import configMiddleware from './config-middleware';
const {
HTTP_HOST,
HTTP_PORT,
} = process.env;
export const createHttpServer = async (latus) => {
const {
config: {
'@latus/http/server': {
build,
devPort,
host,
port,
trust,
},
},
} = latus;
const app = express();
app.set('trust proxy', trust);
const httpServer = createServer(app);
latus.set('%http', httpServer);
httpServer.app = app;
const requestMiddleware = (req, res, next) => {
latus.invokeMiddleware('@latus/http/server/request', req, res, next);
};
const routes = arrayFlatten(latus.invokeFlat('@latus/http/routes'));
routes.forEach(({method, path, handler}) => app[method](path, requestMiddleware, handler));
// Serve latus.
app.get('/latus.config.js', requestMiddleware, configMiddleware(latus));
app.use(express.static(join(process.cwd(), build)));
// eslint-disable-next-line no-eval
if ('production' !== eval('process.env.NODE_ENV')) {
const middlewares = Object.keys(await clientPlugins(latus))
.map((path) => Latus.runtimePath(path))
.filter((path) => !!Latus.runtimePath(`${path}/test`))
.map((path) => {
// eslint-disable-next-line no-eval
const staticPath = dirname(eval('require').resolve(path));
return express.static(staticPath);
});
for (let i = 0; i < middlewares.length; i++) {
app.use(middlewares[i]);
}
const proxy = httpProxy.createProxyServer({
secure: false,
target: `http://127.0.0.1:${devPort}`,
});
proxy.on('proxyRes', async (proxyRes, req, res) => {
if ('text/html; charset=UTF-8' === proxyRes.headers['content-type']) {
requestMiddleware(req, res, () => {
res.setHeader('Content-Type', proxyRes.headers['content-type']);
proxyRes.pipe(res);
});
}
else {
res.setHeader(
'Content-Type',
// ???
'/__webpack_hmr' === req.url ? 'text/event-stream' : proxyRes.headers['content-type'],
);
proxyRes.pipe(res);
}
});
proxy.on('error', (err, req, res) => {
if (res instanceof ServerResponse) {
res.status(502).end('Bad Gateway (WDS)');
}
});
app.all('*', (req, res) => proxy.web(req, res, {selfHandleResponse: true}));
httpServer.on('upgrade', (req, socket, head) => proxy.ws(req, socket, head));
httpServer.on('close', () => proxy.close());
}
else {
app.use(express.static(join(__dirname, 'client')));
app.get('*', async (req, res) => {
res.setHeader('Content-Type', 'text/html; charset=UTF-8');
const stream = createReadStream(join(process.cwd(), build, 'index.html'));
stream.pipe(res);
});
}
return new Promise((resolve, reject) => {
const serverPort = HTTP_PORT || port;
const serverHost = HTTP_HOST || host;
const args = [serverPort];
if (serverHost) {
args.push(serverHost);
}
args.push(async (error) => {
if (error) {
return reject(error);
}
await Promise.all(latus.invokeFlat('@latus/http/server/up', httpServer));
process.stdout.write(`HTTP server up @ ${HTTP_HOST || host}:${HTTP_PORT || port}!\n`);
resolve();
return undefined;
});
httpServer.listen(...args);
});
};
export const destroyHttpServer = (httpServer) => {
if (!httpServer) {
return;
}
httpServer.close();
process.stdout.write('HTTP server down!\n');
};