import path from 'path' ; import fs from 'fs' ; import urlJoin from 'url-join' ; import type { NormalizedConfig , IAppContext } from '@modern-js/core' ; import { isPlainObject , removeLeadingSlash , getEntryOptions , SERVER_BUNDLE_DIRECTORY , MAIN_ENTRY_NAME , removeTailSlash , } from '@modern-js/utils' ; import type { Entrypoint , ServerRoute } from '@modern-js/types' ; import { walkDirectory } from './utils' ; param baseUrl param routes returns const applyBaseUrl = ( baseUrl , routes ) : ServerRoute [ ] => { if ( baseUrl ) { if ( Array . isArray ( baseUrl ) ) { return baseUrl . reduce < ServerRoute [ ] > ( ( previous , current ) => [ ... previous , ... applyBaseUrl ( current , routes ) ] , [ ] ) ; } else { return routes . map ( route => { const urlPath = urlJoin ( baseUrl , route . urlPath ) ; return { ... route , urlPath : urlPath === '/' ? urlPath : removeTailSlash ( urlPath ) , } ; } ) ; } } return routes ; } ; param original param routeOptions returns const applyRouteOptions = ( original , routeOptions ) : ServerRoute [ ] => { const { route , disableSpa } = routeOptions ; original . isSPA = ! disableSpa ; ! original . isSPA && ( original . entryPath = path . dirname ( original . entryPath ) ) ; let routes ; if ( route ) { if ( Array . isArray ( route ) ) { routes = route . map ( url => { if ( isPlainObject ( url ) ) { const { path : urlPath , ... other } = url as Record < string , string > ; return { ... original , ... other , urlPath , } ; } else { return { ... original , urlPath : url , } ; } } ) ; } else if ( isPlainObject ( route ) ) { const { path : urlPath , ... other } = route as Record < string , string > ; routes = [ { ... original , ... other , urlPath , } , ] ; } else { routes = [ { ... original , urlPath : route , } , ] ; } } else { routes = [ original ] ; } return routes ; } ; param entrypoints param config returns const collectHtmlRoutes = ( entrypoints , appContext , config ) : ServerRoute [ ] => { const { output : { htmlPath , disableHtmlFolder , enableModernMode } , server : { baseUrl , routes , ssr , ssrByEntries } , } = config ; const { packageName } = appContext ; let htmlRoutes = entrypoints . reduce < ServerRoute [ ] > ( ( previous , { entryName } ) => { const isSSR = Boolean ( getEntryOptions ( entryName , ssr , ssrByEntries , packageName ) ) ; let route = { urlPath : `/${ entryName === MAIN_ENTRY_NAME ? '' : entryName }` , entryName , entryPath : removeLeadingSlash ( path . posix . normalize ( `${ htmlPath ! }/${ entryName }${ disableHtmlFolder ? '.html' : '/index.html' }` ) ) , isSPA : true , isSSR , enableModernMode : Boolean ( enableModernMode ) , bundle : isSSR ? `${ SERVER_BUNDLE_DIRECTORY }/${ entryName }.js` : undefined , } ; if ( routes ?. hasOwnProperty ( entryName ) ) { const routeOptions = isPlainObject ( routes [ entryName ] ) ? ( routes [ entryName ] as { route : string | string [ ] ; disableSpa ? : boolean ; } ) : { route : routes [ entryName ] as string } ; route = applyRouteOptions ( route , routeOptions ) ; } return Array . isArray ( route ) ? [ ... previous , ... route ] : [ ... previous , route ] ; } , [ ] ) ; htmlRoutes = applyBaseUrl ( baseUrl , htmlRoutes ) ; return htmlRoutes ; } ; param appContext param config returns const collectStaticRoutes = ( appContext , config ) : ServerRoute [ ] => { const { appDirectory } = appContext ; const { source : { configDir } , server : { publicRoutes = { } } , } = config ; const publicFolder = path . resolve ( appDirectory , configDir ! , 'public' ) ; return fs . existsSync ( publicFolder ) ? walkDirectory ( publicFolder ) . map ( filePath => { const urlPath = `${ urlJoin ( toPosix ( filePath ) . slice ( toPosix ( publicFolder ) . length ) ) }` ; return { urlPath : publicRoutes [ removeLeadingSlash ( urlPath ) ] || urlPath , isSPA : true , isSSR : false , entryPath : toPosix ( path . relative ( path . resolve ( appDirectory , configDir ! ) , filePath ) ) , } ; } ) : [ ] ; } ; export const getServerRoutes = ( entrypoints , { appContext , config , } ) : ServerRoute [ ] => [ ... collectHtmlRoutes ( entrypoints , appContext , config ) , ... collectStaticRoutes ( appContext , config ) , ] ; const toPosix = ( pathStr ) => pathStr . split ( path . sep ) . join ( path . posix . sep ) ;