import type * as d from '../../declarations' ; import { buildError , catchError , isFunction , isString } from '@utils' ; import { crawlAnchorsForNextUrls } from './crawl-urls' ; import { getWriteFilePathFromUrlPath } from './prerendered-write-path' ; import { relative } from 'path' ; export const initializePrerenderEntryUrls = ( results , manager ) => { const entryAnchors = [ ] ; if ( Array . isArray ( manager . prerenderConfig . entryUrls ) ) { for ( const entryUrl of manager . prerenderConfig . entryUrls ) { const entryAnchor = { href : entryUrl , } ; entryAnchors . push ( entryAnchor ) ; } } else { const entryAnchor = { href : manager . outputTarget . baseUrl , } ; entryAnchors . push ( entryAnchor ) ; } for ( const entryAnchor of entryAnchors ) { try { new URL ( entryAnchor . href , manager . outputTarget . baseUrl ) ; } catch ( e ) { const diagnostic = buildError ( results . diagnostics ) ; diagnostic . header = `Invalid Prerender Entry Url: ${ entryAnchor . href }` ; diagnostic . messageText = `Entry Urls must include the protocol and domain of the site being prerendered.` ; return ; } } const base = new URL ( manager . outputTarget . baseUrl ) ; const hrefs = crawlAnchorsForNextUrls ( manager . prerenderConfig , results . diagnostics , base , base , entryAnchors ) ; for ( const href of hrefs ) { addUrlToPendingQueue ( manager , href , '#entryUrl' ) ; } } ; const addUrlToPendingQueue = ( manager , queueUrl , fromUrl ) => { if ( ! isString ( queueUrl ) || queueUrl === '' ) { return ; } if ( manager . urlsPending . has ( queueUrl ) ) { return ; } if ( manager . urlsProcessing . has ( queueUrl ) ) { return ; } if ( manager . urlsCompleted . has ( queueUrl ) ) { return ; } manager . urlsPending . add ( queueUrl ) ; if ( manager . isDebug ) { const url = new URL ( queueUrl , manager . outputTarget . baseUrl ) . pathname ; const from = fromUrl . startsWith ( '#' ) ? fromUrl : new URL ( fromUrl , manager . outputTarget . baseUrl ) . pathname ; manager . config . logger . debug ( `prerender queue: ${ url } (from ${ from })` ) ; } } ; export const drainPrerenderQueue = ( results , manager ) => { const nextUrl = manager . urlsPending . values ( ) . next ( ) ; if ( ! nextUrl . done ) { if ( manager . urlsProcessing . size > manager . maxConcurrency ) { setTimeout ( ( ) => drainPrerenderQueue ( results , manager ) ) ; } else { const url = nextUrl . value ; manager . urlsPending . delete ( url ) ; manager . urlsProcessing . add ( url ) ; prerenderUrl ( results , manager , url ) ; if ( manager . urlsProcessing . size < manager . maxConcurrency ) { manager . config . sys . nextTick ( ( ) => drainPrerenderQueue ( results , manager ) ) ; } } } if ( manager . urlsProcessing . size === 0 && manager . urlsPending . size === 0 ) { if ( isFunction ( manager . resolve ) ) { manager . resolve ( ) ; manager . resolve = null ; } } } ; const prerenderUrl = async ( results , manager , url ) => { let previewUrl = url ; try { previewUrl = new URL ( url ) . pathname ; let timespan ; if ( manager . isDebug ) { timespan = manager . config . logger . createTimeSpan ( `prerender start: ${ previewUrl }` , true ) ; } const prerenderRequest = { appDir : manager . outputTarget . appDir , baseUrl : manager . outputTarget . baseUrl , buildId : results . buildId , componentGraphPath : manager . componentGraphPath , devServerHostUrl : manager . devServerHostUrl , hydrateAppFilePath : manager . hydrateAppFilePath , isDebug : manager . isDebug , prerenderConfigPath : manager . prerenderConfigPath , staticSite : manager . staticSite , templateId : manager . templateId , url : url , writeToFilePath : getWriteFilePathFromUrlPath ( manager , url ) , } ; const urlResults = await manager . prerenderUrlWorker ( prerenderRequest ) ; if ( manager . isDebug ) { const filePath = relative ( manager . config . rootDir , urlResults . filePath ) ; const hasError = urlResults . diagnostics . some ( ( d ) => d . level === 'error' ) ; if ( hasError ) { timespan . finish ( `prerender failed: ${ previewUrl }, ${ filePath }` , 'red' ) ; } else { timespan . finish ( `prerender finish: ${ previewUrl }, ${ filePath }` ) ; } } manager . diagnostics . push ( ... urlResults . diagnostics ) ; if ( Array . isArray ( urlResults . anchorUrls ) ) { for ( const anchorUrl of urlResults . anchorUrls ) { addUrlToPendingQueue ( manager , anchorUrl , url ) ; } } } catch ( e ) { catchError ( manager . diagnostics , e ) ; } manager . urlsProcessing . delete ( url ) ; manager . urlsCompleted . add ( url ) ; results . urls ++ ; const urlsCompletedSize = manager . urlsCompleted . size ; if ( manager . progressLogger && urlsCompletedSize > 1 ) { manager . progressLogger . update ( `           prerendered ${ urlsCompletedSize } urls: ${ manager . config . logger . dim ( previewUrl ) }` ) ; } manager . config . sys . nextTick ( ( ) => drainPrerenderQueue ( results , manager ) ) ; } ;