Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 55 additions & 24 deletions packages/angular/ssr/src/app-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, EntryPointExports>();

/**
* Renders a response for the given HTTP request using the server application.
*
Expand All @@ -65,12 +70,12 @@ export class AngularAppEngine {
async render(request: Request, requestContext?: unknown): Promise<Response | null> {
// 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
Expand All @@ -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<EntryPointExports>) | 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.
Expand All @@ -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<EntryPointExports | undefined> {
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<EntryPointExports | undefined> {
const { entryPoints, basePath } = this.manifest;
if (entryPoints.size === 1) {
return this.getEntryPointExports('');
}

const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath);

return this.getEntryPointExports(potentialLocale);
}
}