diff --git a/packages/xarc-app-dev/src/lib/dev-admin/dev-http.ts b/packages/xarc-app-dev/src/lib/dev-admin/dev-http.ts index 3f0bb069e..f948cf008 100644 --- a/packages/xarc-app-dev/src/lib/dev-admin/dev-http.ts +++ b/packages/xarc-app-dev/src/lib/dev-admin/dev-http.ts @@ -1,10 +1,15 @@ /* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable no-console */ + import { createReadStream } from "fs"; -import { createServer, IncomingMessage, RequestListener, ServerResponse } from "http"; +import { Readable } from "stream"; +import { getType } from "mime"; +import { createServer, Server } from "http"; import * as Url from "url"; -import { resolve } from "path"; -const Middleware = require("./middleware"); +import { resolve as pathResolve } from "path"; +const Middleware = require("./middleware"); +const FakeRes = require("../fake-res"); export interface DevHttpServerOptions { port: number; host: string; @@ -15,11 +20,10 @@ export type HttpRequestEvent = "connect" | "response" | "timeout" | "close" | "f export type HttpServerEvent = "open" | "close" | "listening" | "error"; export interface DevHttpServer { - webpackDevHttpPlugin: RequestListener; start: () => void; - stop?: () => void; - addRequestListener: (event: HttpRequestEvent, handler: any) => void; - addServerEventListener: (event: HttpServerEvent, hander: any) => void; + stop: () => void; + httpServer?: Server; + addListener: (event: HttpServerEvent, hander: any) => void; } export const setupHttpDevServer = function({ @@ -39,53 +43,57 @@ export const setupHttpDevServer = function({ middleware.setup(); - const requestEventHooks = {}; + const server: Server = createServer(async (req, res) => { + try { + const next1 = await middleware.process(req, res, { + skip: () => middleware.canContinue, + replyHtml: html => + res.writeHead(200, { "Content-Type": "text/html" }).end(`${html}`), + replyError: err => res.writeHead(500, err) && res.end(), + replyNotFound: () => res.writeHead(404, "dev server express Not Found") && res.end(), //res.status(404).send("dev server express Not Found"), + replyStaticData: data => { + res.writeHead(200, { "Content-Type": getType(req.url) }); + Readable.from(data).pipe(res); + }, + replyFile: file => + res.writeHead(200, { "Content-Type": getType(file) }) && + createReadStream(pathResolve(file)).pipe(res) + }); - const webpackDevHttpPlugin: RequestListener = function( - req: IncomingMessage, - res: ServerResponse - ) { - Object.keys(requestEventHooks).map(eventName => { - req.addListener(eventName, event => requestEventHooks[eventName]({ ...event, ...req })); - }); - middleware.process(req, res, { - skip: () => Promise.resolve(), - replyHtml: html => { - res - .writeHead(200, { - "Content-Type": "text/html" - }) - .end(`${html}`); - }, - replyError: err => { - res.writeHead(500, err); - }, - replyNotFound: () => res.writeHead(404, "dev server express Not Found"), //res.status(404).send("dev server express Not Found"), - replyStaticData: data => { - const type = require("mime").getType(req.url); - res.writeHead(200, { - "Content-Type": type - }); - res.end(data); - }, - replyFile: file => createReadStream(resolve(file)).pipe(res) - }); - }; - const server = createServer(webpackDevHttpPlugin); + if (next1 !== middleware.canContinue) return; + + const devFakeRes = new FakeRes(); + await middleware.devMiddleware(req, devFakeRes, () => Promise.resolve()); + if (devFakeRes.responded) { + devFakeRes.httpRespond(res); + return; + } + + middleware.hotMiddleware(req, res, err => { + if (err) { + console.error("webpack hot middleware error", err); + res.writeHead(500, err.message); + } + }); + } catch (e) { + console.error("webpack dev middleware error", e); + res.statusCode = 500; + res.end(e.message); + } + }); return { start: () => server.listen(port, host), - webpackDevHttpPlugin, - addServerEventListener: (event: HttpServerEvent, cb) => { - server.addListener(event.toString(), cb); - }, stop: () => { server.close(function() { /* eslint-disable no-console */ console.log("Server closed!"); }); }, - addRequestListener: (event: HttpRequestEvent, cb: any) => (requestEventHooks[event] = cb) + addListener: (event: HttpServerEvent, cb) => { + server.addListener(event.toString(), cb); + }, + httpServer: server }; }; export const setup = setupHttpDevServer; diff --git a/packages/xarc-app-dev/src/lib/dev-admin/dev-server.ts b/packages/xarc-app-dev/src/lib/dev-admin/dev-server.ts index 5e2fa96b7..a2cf915d4 100644 --- a/packages/xarc-app-dev/src/lib/dev-admin/dev-server.ts +++ b/packages/xarc-app-dev/src/lib/dev-admin/dev-server.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable global-require, no-console */ -import { DevHttpServer, setupHttpDevServer } from "./dev-http"; +import { setupHttpDevServer } from "./dev-http"; import { createServer } from "http"; const ck = require("chalker"); @@ -21,19 +21,20 @@ if (process.env.WEBPACK_DEV === undefined) { } if (createServer) { - const devHttpServer: DevHttpServer = setupHttpDevServer({ + const devHttpServer = setupHttpDevServer({ host: archetype.webpack.devHostname, port: archetype.webpack.devPort }); - devHttpServer.start(); - devHttpServer.addServerEventListener("error", err => { + devHttpServer.addListener("error", err => { console.error(ck`HTTP webpack dev server having an error${err}`); }); - devHttpServer.addServerEventListener("listening", e => { + + devHttpServer.addListener("listening", () => console.log( ck`Node.js webpack dev server listening on port ${archetype.webpack.devPort}` - ); - }); + ) + ); + devHttpServer.start(); } else if (fastifyServer) { fastifyServer({ electrode: { diff --git a/packages/xarc-app-dev/src/lib/fake-res.ts b/packages/xarc-app-dev/src/lib/fake-res.ts index a562eff9c..6a3b4a0fa 100644 --- a/packages/xarc-app-dev/src/lib/fake-res.ts +++ b/packages/xarc-app-dev/src/lib/fake-res.ts @@ -87,6 +87,13 @@ class FakeRes extends EventEmitter { res.body = this._content; return res; } + + httpRespond(res) { + res.writeHeader(this._statusCode, this._headers); + res.statusCode = this._statusCode; + res.end(this._content); + return res; + } } module.exports = FakeRes;