import path from 'path' ; import express from 'express' ; import webpack from 'webpack' ; import webpackDevMiddleware from 'webpack-dev-middleware' ; import webpackHotMiddleware from 'webpack-hot-middleware' ; import { assetsToArray } from '../utils/utils' ; import pawConfig from '../config' ; import directories from '../webpack/utils/directories' ; import wHandler from '../webpack' ; import requireFromString from '../webpack/utils/requireFromString' ; import normalizeAssets from '../webpack/utils/normalizeAssets' ; console . log ( `
=========================================================
  Compiling files.
  This may take time depending on the application size.
  Thank you for your patience.
=========================================================
` ) ; try { const serverConfig = wHandler . getConfig ( process . env . PAW_ENV , 'server' ) ?. [ 0 ] ; const webConfig = wHandler . getConfig ( process . env . PAW_ENV , 'web' ) ?. [ 0 ] ; const devServerConfig = { serverSideRender : pawConfig . serverSideRender , publicPath : pawConfig . resourcesBaseUrl , } ; const processEnv = process . env ; const isVerbose = processEnv . PAW_VERBOSE === 'true' ; const stats = { colors : true , reasons : isVerbose , entrypoints : isVerbose , modules : isVerbose , moduleTrace : isVerbose , assets : true , warnings : isVerbose , errors : true , cachedAssets : isVerbose , version : isVerbose , } ; const commonOptions = { stats } ; const serverOptions = { ... commonOptions , ... devServerConfig , } ; const webOptions = { ... commonOptions , serverSideRender : true , publicPath : pawConfig . resourcesBaseUrl , } ; const serverCompiler = webpack ( serverConfig ) ; const webCompiler = webpack ( webConfig ) ; const app = express ( ) ; const PAW_GLOBAL = { } ; app . set ( 'x-powered-by' , 'PawJS' ) ; const serverMiddleware = webpackDevMiddleware ( serverCompiler , serverOptions ) ; app . use ( serverMiddleware ) ; const webMiddleware = webpackDevMiddleware ( webCompiler , webOptions ) ; app . use ( webMiddleware ) ; let startServer = ( ) => { } ; let checkTimeout ; let checkRetries = 0 ; const checkInNext2Seconds = ( ) => { if ( checkTimeout ) { clearTimeout ( checkTimeout ) ; } checkTimeout = setTimeout ( ( ) => { checkRetries += 1 ; startServer ( ) ; } , 2000 ) ; } ; const getCommonServer = ( ) => { if ( checkRetries < 10 && ! serverMiddleware ?. context ?. stats ) { checkInNext2Seconds ( ) ; return ; } if ( checkTimeout ) { clearTimeout ( checkTimeout ) ; } const mfs = serverMiddleware . context . outputFileSystem as any ; const serverFile = serverMiddleware . getFilenameFromUrl ( `${ serverOptions . publicPath }server.js` ) ; if ( ! serverFile ) { throw new Error ( `Cannot find server.js at ${ serverOptions . publicPath }server.js` ) ; } const serverContent = mfs . readFileSync ( serverFile , 'utf-8' ) ; const nodePath = process . env . NODE_PATH || '' ; return requireFromString ( serverContent , { appendPaths : nodePath . split ( path . delimiter ) , } ) ; } ; if ( pawConfig . hotReload ) { app . use ( webpackHotMiddleware ( webCompiler , { log : false , path : '/__hmr_update' , heartbeat : 2000 , } ) ) ; } app . use ( pawConfig . appRootUrl || '' , express . static ( path . join ( ( directories . src || '' ) , 'public' ) ) ) ; /**
     * Below is where the magic happens!
     * We import the compiled server.js file as string and run it as module
     * thus we can get a fast experience of compilation and developer can
     * develop code with SSR enabled.
     */ app . use ( ( req , res , next ) => { const mfs = serverMiddleware . context . outputFileSystem as any ; const fileNameFromUrl = serverMiddleware . getFilenameFromUrl ( serverOptions . publicPath + req . path ) || '' ; if ( fileNameFromUrl . indexOf ( 'favicon.ico' ) !== - 1 || ( mfs . existsSync ( fileNameFromUrl ) && mfs . statSync ( fileNameFromUrl ) . isFile ( ) ) ) { return next ( ) ; } let commonServerMiddleware ; try { const commonServer = getCommonServer ( ) ; const expressApp = commonServer . app ; commonServerMiddleware = commonServer . default ; const { jsDependencyMap , cssDependencyMap , ... assets } = normalizeAssets ( webMiddleware ?. context ?. stats ?? null ) ; expressApp . locals . assets = assetsToArray ( assets ) ; expressApp . locals . cssDependencyMap = cssDependencyMap ; expressApp . locals . jsDependencyMap = jsDependencyMap ; return commonServerMiddleware ( req , res , next , PAW_GLOBAL ) ; } catch ( ex ) { console . log ( ex ) ; } return next ( ) ; } ) ; let serverStarted = false ; startServer = ( ) => { if ( serverStarted ) return ; let beforeStart ; let afterStart ; try { const commonServer = getCommonServer ( ) ; if ( ! commonServer ) return ; beforeStart = commonServer . beforeStart ; afterStart = commonServer . afterStart ; } catch ( ex ) { console . error ( ex ) ; } const nodeServerConfig = { port : pawConfig . port , host : pawConfig . host , } ; beforeStart ( nodeServerConfig , PAW_GLOBAL , ( err ) => { if ( err ) { console . error ( err ) ; return ; } app . listen ( parseInt ( nodeServerConfig . port || '9090' , 10 ) , nodeServerConfig . host || '0.0.0.0' , ( ) => { serverStarted = true ; console . log ( `

===================================================
  Listening to http://${ nodeServerConfig . host }:${ nodeServerConfig . port }
  Open the above url in your browser.
===================================================` ) ; afterStart ( PAW_GLOBAL ) ; } ) ; } ) ; } ; webCompiler . hooks . done . tap ( 'InformWebCompiled' , startServer ) ; serverCompiler . hooks . done . tap ( 'InformServerCompiled' , startServer ) ; } catch ( ex ) { console . error ( ex ) ; }