import express from 'express'; import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; import { Compiler } from 'webpack'; import { Log } from '@spine/logger'; import { notify } from '@erect/server/utils/notify'; import { config } from '@erect/core/config/index'; import { ListenerManager } from './listenerManager'; import { plugin } from './plugin'; export class HotClientServer { webpackDevMiddleware: webpackDevMiddleware.WebpackDevMiddleware; listenerManager: ListenerManager; constructor(compiler: Compiler, log: Log) { const app = express(); const publicPath = compiler.options.output != null ? compiler.options.output.publicPath || '' : ''; const httpPathRegex = /^(https?:)?\/\/(.*):([\d]{1,5})/i; const httpPath = publicPath; if (!httpPathRegex.test(httpPath)) { throw new Error( 'You must supply an absolute public path to a development build of a web target bundle as it will be hosted on a seperate development server to any node target bundles.', ); } this.webpackDevMiddleware = webpackDevMiddleware(compiler, { // Ensure that the public path is taken from the compiler webpack config // as it will have been created as an absolute path to avoid conflicts // with an node servers. publicPath, quiet: true, noInfo: true, headers: { 'Access-Control-Allow-Origin': `http://${config.host}`, }, } as any); app.use(this.webpackDevMiddleware as any); app.use(webpackHotMiddleware(compiler)); const listener = app.listen(config.clientDevServerPort, config.listenAddress); this.listenerManager = new ListenerManager(listener, 'client', log); compiler.hooks.beforeCompile.tap(plugin, () => { log.info('Building new bundle...'); }); compiler.hooks.done.tap(plugin, (stats: any) => { if (stats.hasErrors()) { log.error('Build failed'); notify('Build failed, please check the console for more information.'); console.error(stats.toString()); } }); } async dispose() { await this.listenerManager !== undefined ? this.listenerManager.dispose() : Promise.resolve(); await new Promise((resolve) => { this.webpackDevMiddleware.close(() => resolve()); }); } }