diff --git a/packages/angular/ssr/src/app-engine.ts b/packages/angular/ssr/src/app-engine.ts index 623bbae8bc4d..9862901c7c4f 100644 --- a/packages/angular/ssr/src/app-engine.ts +++ b/packages/angular/ssr/src/app-engine.ts @@ -47,6 +47,11 @@ export class AngularAppEngine { */ private readonly manifest = getAngularAppEngineManifest(); + /** + * A cache that holds entry points, keyed by their potential locale string. + */ + private readonly entryPointsCache = new Map(); + /** * Renders a response for the given HTTP request using the server application. * @@ -65,12 +70,12 @@ export class AngularAppEngine { async render(request: Request, requestContext?: unknown): Promise { // Skip if the request looks like a file but not `/index.html`. const url = new URL(request.url); - const entryPoint = this.getEntryPointFromUrl(url); + const entryPoint = await this.getEntryPointExportsForUrl(url); if (!entryPoint) { return null; } - const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = await entryPoint(); + const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = entryPoint; // Note: Using `instanceof` is not feasible here because `AngularServerApp` will // be located in separate bundles, making `instanceof` checks unreliable. // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion @@ -80,28 +85,6 @@ export class AngularAppEngine { return serverApp.render(request, requestContext); } - /** - * Retrieves the entry point path and locale for the Angular server application based on the provided URL. - * - * This method determines the appropriate entry point and locale for rendering the application by examining the URL. - * If there is only one entry point available, it is returned regardless of the URL. - * Otherwise, the method extracts a potential locale identifier from the URL and looks up the corresponding entry point. - * - * @param url - The URL used to derive the locale and determine the appropriate entry point. - * @returns A function that returns a promise resolving to an object with the `EntryPointExports` type, - * or `undefined` if no matching entry point is found for the extracted locale. - */ - private getEntryPointFromUrl(url: URL): (() => Promise) | undefined { - const { entryPoints, basePath } = this.manifest; - if (entryPoints.size === 1) { - return entryPoints.values().next().value; - } - - const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath); - - return entryPoints.get(potentialLocale); - } - /** * Retrieves HTTP headers for a request associated with statically generated (SSG) pages, * based on the URL pathname. @@ -120,4 +103,52 @@ export class AngularAppEngine { return new Map(headers); } + + /** + * Retrieves the exports for a specific entry point, caching the result. + * + * @param potentialLocale - The locale string used to find the corresponding entry point. + * @returns A promise that resolves to the entry point exports or `undefined` if not found. + */ + private async getEntryPointExports( + potentialLocale: string, + ): Promise { + const cachedEntryPoint = this.entryPointsCache.get(potentialLocale); + if (cachedEntryPoint) { + return cachedEntryPoint; + } + + const { entryPoints } = this.manifest; + const entryPoint = entryPoints.get(potentialLocale); + if (!entryPoint) { + return undefined; + } + + const entryPointExports = await entryPoint(); + this.entryPointsCache.set(potentialLocale, entryPointExports); + + return entryPointExports; + } + + /** + * Retrieves the entry point for a given URL by determining the locale and mapping it to + * the appropriate application bundle. + * + * This method determines the appropriate entry point and locale for rendering the application by examining the URL. + * If there is only one entry point available, it is returned regardless of the URL. + * Otherwise, the method extracts a potential locale identifier from the URL and looks up the corresponding entry point. + * + * @param url - The URL of the request. + * @returns A promise that resolves to the entry point exports or `undefined` if not found. + */ + private getEntryPointExportsForUrl(url: URL): Promise { + const { entryPoints, basePath } = this.manifest; + if (entryPoints.size === 1) { + return this.getEntryPointExports(''); + } + + const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath); + + return this.getEntryPointExports(potentialLocale); + } }