import * as path from 'path' ; import express , { RequestHandler , Express } from 'express' ; import type { Request , Response } from 'express' ; import cookieParser from 'cookie-parser' ; import { createPlugin } from '@modern-js/server-plugin' ; import { requireModule } from '@modern-js/bff-utils' ; import { fs , createDebugger } from '@modern-js/utils' ; import finalhandler from 'finalhandler' ; import { run } from './context' ; import registerRoutes from './registerRoutes' ; const debug = createDebugger ( 'express' ) ; interface FrameConfig { middleware : ( RequestHandler | string ) [ ] ; } export type Mode = 'function' | 'framework' ; const findAppModule = async ( apiDir ) => { const exts = [ '.ts' , '.js' ] ; const paths = exts . map ( ext => path . resolve ( apiDir , `app${ ext }` ) ) ; for ( const filename of paths ) { if ( await fs . pathExists ( filename ) ) { return requireModule ( filename ) ; } } return null ; } ; const initMiddlewares = ( middleware , app ) => { middleware . forEach ( middlewareItem => { const middlewareFunc = typeof middlewareItem === 'string' ? requireModule ( middlewareItem ) : middlewareItem ; app . use ( middlewareFunc ) ; } ) ; } ; const useRun = ( app ) => { app . use ( ( req , res , next ) => { run ( { req , res } , next ) ; } ) ; } ; const initApp = ( app ) => { app . use ( cookieParser ( ) ) ; app . use ( express . text ( ) ) ; app . use ( express . urlencoded ( { extended : true } ) ) ; app . use ( express . json ( ) ) ; return app ; } ; export default createPlugin ( ( ) => ( { async prepareApiServer ( { pwd , mode , config } ) { let app ; const apiDir = path . join ( pwd , './api' ) ; if ( mode === 'framework' ) { app = await findAppModule ( apiDir ) ; if ( ! app || ! app . use ) { app = express ( ) ; } initApp ( app ) ; if ( config ) { const { middleware } = config as FrameConfig ; initMiddlewares ( middleware , app ) ; } useRun ( app ) ; registerRoutes ( app ) ; } else if ( mode === 'function' ) { app = express ( ) ; initApp ( app ) ; if ( config ) { const { middleware } = config as FrameConfig ; initMiddlewares ( middleware , app ) ; } useRun ( app ) ; registerRoutes ( app ) ; } else { throw new Error ( `mode must be function or framework` ) ; } return ( req , res ) => new Promise ( ( resolve , reject ) => { const handler = ( err ) => { if ( err ) { return reject ( err ) ; } return finalhandler ( req , res , { } ) ( null ) ; } ; res . on ( 'finish' , ( err ) => { if ( err ) { return reject ( err ) ; } return resolve ( ) ; } ) ; return app ( req as Request , res as Response , handler ) ; } ) ; } , prepareWebServer ( { config } ) { const app = express ( ) ; initApp ( app ) ; if ( config ) { const { middleware } = config as FrameConfig ; debug ( 'web middleware' , middleware ) ; initMiddlewares ( middleware , app ) ; } return ( req , res ) => new Promise ( ( resolve , reject ) => { const handler = ( err ) => { if ( err ) { return reject ( err ) ; } if ( res . headersSent && res . statusCode !== 200 ) { finalhandler ( req , res , { } ) ( null ) ; } return resolve ( ) ; } ; res . on ( 'finish' , ( err ) => { if ( err ) { return reject ( err ) ; } return resolve ( ) ; } ) ; return app ( req as Request , res as Response , handler ) ; } ) ; } , } ) , { name : '@modern-js/plugin-express' , pre : [ '@modern-js/plugin-bff' ] , } ) as any ;