import path from 'path' ; import { logger , PLUGIN_SCHEMAS } from '@modern-js/utils' ; import { createPlugin , useAppContext , useResolvedConfigContext , } from '@modern-js/core' ; import { generatePath } from 'react-router-dom' ; import { AgreedRoute , AgreedRouteMap , EntryPoint , ExtendOutputConfig , SSG , SsgRoute , } from './types' ; import { formatOutput , isDynamicUrl , readJSONSpec , standardOptions , writeJSONSpec , } from './libs/util' ; import { createServer } from './server' ; import { writeHtmlFile } from './libs/output' ; import { replaceRoute } from './libs/replace' ; import { makeRoute } from './libs/make' ; export default createPlugin ( ( ( ) => { const agreedRouteMap = { } ; return { validateSchema ( ) { return PLUGIN_SCHEMAS [ '@modern-js/plugin-ssg' ] ; } , modifyFileSystemRoutes ( { entrypoint , routes , } ) { const { entryName } = entrypoint ; agreedRouteMap [ entryName ] = routes ; return { entrypoint , routes } ; } , async afterBuild ( ) { const resolvedConfig = useResolvedConfigContext ( ) ; const appContext = useAppContext ( ) ; const { appDirectory , entrypoints } = appContext ; const { output } = resolvedConfig ; const { ssg , path : outputPath } = output as typeof output & ExtendOutputConfig ; const ssgOptions = Array . isArray ( ssg ) ? ssg . pop ( ) : ssg ; if ( ! ssgOptions ) { return ; } const buildDir = path . join ( appDirectory , outputPath as string ) ; const routes = readJSONSpec ( buildDir ) ; const pageRoutes = routes . filter ( route => ! route . isApi ) ; const apiRoutes = routes . filter ( route => route . isApi ) ; if ( pageRoutes . length === 0 ) { return ; } const intermediateOptions = standardOptions ( ssgOptions , entrypoints ) ; if ( ! intermediateOptions ) { return ; } const ssgRoutes = [ ] ; pageRoutes . forEach ( pageRoute => { const { entryName , entryPath } = pageRoute ; const agreedRoutes = agreedRouteMap [ entryName as string ] ; let entryOptions = intermediateOptions [ entryName as string ] ; if ( ! agreedRoutes ) { if ( ! entryOptions ) { return ; } if ( entryOptions === true ) { ssgRoutes . push ( { ... pageRoute , output : entryPath } ) ; } else if ( entryOptions . routes ?. length > 0 ) { const { routes : enrtyRoutes , headers } = entryOptions ; enrtyRoutes . forEach ( route => { ssgRoutes . push ( makeRoute ( pageRoute , route , headers ) ) ; } ) ; } } else { if ( entryOptions === false ) { return ; } if ( ! entryOptions || entryOptions === true ) { entryOptions = { preventDefault : [ ] , routes : [ ] , headers : { } } ; } const { preventDefault = [ ] , routes : userRoutes = [ ] , headers , } = entryOptions ; if ( userRoutes . length > 0 ) { userRoutes . forEach ( route => { if ( typeof route === 'string' ) { ssgRoutes . push ( makeRoute ( pageRoute , route , headers ) ) ; } else if ( Array . isArray ( route . params ) ) { route . params . forEach ( param => { ssgRoutes . push ( makeRoute ( pageRoute , { ... route , url : generatePath ( route . url , param ) } , headers ) ) ; } ) ; } else { ssgRoutes . push ( makeRoute ( pageRoute , route , headers ) ) ; } } ) ; } else { agreedRoutes . filter ( route => ! preventDefault . includes ( route . path ) ) . forEach ( route => { if ( ! isDynamicUrl ( route . path ) ) { ssgRoutes . push ( makeRoute ( pageRoute , route . path , headers ) ) ; } } ) ; } } } ) ; if ( ssgRoutes . length === 0 ) { return ; } ssgRoutes . forEach ( ( ssgRoute ) => { if ( ssgRoute . isSSR ) { const isOriginRoute = pageRoutes . some ( pageRoute => pageRoute . urlPath === ssgRoute . urlPath && pageRoute . entryName === ssgRoute . entryName ) ; if ( isOriginRoute ) { throw new Error ( `ssg can not using with ssr，url - ${ ssgRoute . urlPath }, entry - ${ ssgRoute . entryName ! } ` ) ; } logger . warn ( `new ssg route ${ ssgRoute . urlPath } is using ssr now，maybe from parent route ${ ssgRoute . entryName ! }，close ssr` ) ; } ssgRoute . isSSR = false ; ssgRoute . output = formatOutput ( ssgRoute . output ) ; } ) ; const htmlAry = await createServer ( ssgRoutes , apiRoutes , resolvedConfig , appDirectory ) ; writeHtmlFile ( htmlAry , ssgRoutes , buildDir ) ; replaceRoute ( ssgRoutes , pageRoutes ) ; writeJSONSpec ( buildDir , pageRoutes . concat ( apiRoutes ) ) ; logger . info ( 'ssg Compiled successfully' ) ; } , } ; } ) as any , { name : '@modern-js/plugin-ssg' } ) as any ;