import eachObj from '@tinkoff/utils/object/each' ; import path from 'path' ; import type webpack from 'webpack' ; import type Config from 'webpack-chain' ; import death from 'death' ; import type { Worker } from 'cluster' ; import { createProxyServer } from 'http-proxy' ; import webOutgoing from 'http-proxy/lib/http-proxy/passes/web-outgoing' ; import { PoolState } from 'lightning-pool' ; import type { Container } from '@tinkoff/dippy' ; import type { ConfigManager } from '../../../config/configManager' ; import type { ApplicationConfigEntry } from '../../../typings/configEntry/application' ; import { createWorkerPool } from './workerPool' ; import type { SERVER_TOKEN } from '../tokens' ; import { CLOSE_HANDLER_TOKEN } from '../tokens' ; const EXITED_UNEXPECTEDLY = `

!!!  Child process exited unexpectedly  !!!,


See server logs with details and try to fix the issue,
After code change rebuild will be done automatically


` ; declare module 'webpack' { export class MultiStats { stats : webpack . Stats [ ] ; } } const HOOK_NAME = 'DevServer' ; export const serverRunner = ( { di , config , compiler , configManager , server , } ) => { return async function runDevServer ( ) { const file = `${ Object . keys ( config . entryPoints . entries ( ) ) [ 0 ] }.js` ; const filename = path . resolve ( config . output . get ( 'path' ) , file ) ; const realFilename = `http://${ configManager . staticHost }:${ configManager . staticPort }/${ configManager . build . options . outputServer }/${ file }` ; const serverCompiler = compiler . compilers . find ( ( comp ) => comp . name === 'server' ) ; const fs = serverCompiler . outputFileSystem as any ; const pool = createWorkerPool ( di ) ; let worker ; let serverInvalidated = true ; let workerPort ; let resolveWorkerPort ; let workerPortPromise ; let hasExitedUnexpectedly = false ; const proxy = createProxyServer ( { selfHandleResponse : true , } ) ; death ( { exit : true , uncaughtException : true } ) ( async ( signal , err ) => { await pool . close ( true ) ; if ( err instanceof Error ) { console . error ( err ) ; } process . exit ( 1 ) ; } ) ; if ( ! configManager . noServerRebuild ) { serverCompiler . hooks . invalid . tap ( HOOK_NAME , ( ) => { serverInvalidated = true ; hasExitedUnexpectedly = false ; } ) ; } const waitWorkerPort = async ( ) => { if ( workerPort ) { return workerPort ; } if ( workerPortPromise ) { return workerPortPromise ; } workerPortPromise = new Promise < void > ( ( resolve ) => { resolveWorkerPort = resolve ; } ) ; return workerPortPromise ; } ; proxy . on ( 'proxyReq' , ( proxyReq , req ) => { ( proxyReq as any ) . path = req . url ; } ) ; proxy . on ( 'proxyRes' , ( proxyRes , req , res ) => { if ( ! res . headersSent ) { eachObj ( ( handler ) => { handler ( req , res , proxyRes , { } ) ; } , webOutgoing ) ; } proxyRes . on ( 'aborted' , ( ) => { const contentType = res . getHeader ( 'content-type' ) ; if ( typeof contentType === 'string' && contentType . includes ( 'text/event-stream' ) ) { proxy . emit ( 'error' , Error ( 'aborted' ) , req , res ) ; } } ) ; proxyRes . pipe ( res ) ; } ) ; proxy . on ( 'error' , async ( err , req , res ) => { await waitWorkerPort ( ) ; proxy . web ( req , res as any , { target : `http://localhost:${ workerPort }` } ) ; } ) ; server . on ( 'request' , async ( req , res ) => { if ( hasExitedUnexpectedly ) { res . end ( EXITED_UNEXPECTEDLY ) ; return ; } await waitWorkerPort ( ) ; proxy . web ( req , res , { target : `http://localhost:${ workerPort }` } ) ; } ) ; server . on ( 'upgrade' , ( req , socket , head ) => { proxy . ws ( req , socket , { target : `http://localhost:${ workerPort }` } ) ; } ) ; di . register ( { provide : CLOSE_HANDLER_TOKEN , multi : true , useValue : async ( ) => { proxy . close ( ) ; if ( worker ) { await pool . release ( worker ) ; await pool . close ( true ) ; } } , } ) ; serverCompiler . hooks . beforeCompile . tapPromise ( HOOK_NAME , async ( ) => { if ( pool . state === PoolState . IDLE ) { await pool . start ( ) ; } } ) ; compiler . hooks . done . tap ( HOOK_NAME , async ( stats ) => { if ( serverInvalidated ) { workerPort = null ; workerPortPromise = null ; serverInvalidated = false ; if ( stats . hasErrors ( ) ) { return ; } if ( worker ) { await pool . release ( worker ) ; } worker = await pool . acquire ( ) ; worker . on ( 'exit' , async ( ) => { hasExitedUnexpectedly = true ; workerPort = null ; workerPortPromise = null ; worker = null ; pool . release ( worker ) ; console . error ( EXITED_UNEXPECTEDLY ) ; } ) ; worker . once ( 'message' , ( { cmd , port } ) => { if ( cmd === 'listen' ) { workerPort = port ; resolveWorkerPort ?. ( ) ; } } ) ; worker . send ( { filename : realFilename , script : fs . readFileSync ( filename , 'utf8' ) , } ) ; } } ) ; } ; } ;