Skip to content

Commit 1d70e3b

Browse files
committed
perf(@angular/ssr): cache resolved entry-points
Improve request throughput by 4.34% and reduce latency by caching resolved entry-points.
1 parent 759ec48 commit 1d70e3b

File tree

1 file changed

+55
-24
lines changed

1 file changed

+55
-24
lines changed

packages/angular/ssr/src/app-engine.ts

+55-24
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export class AngularAppEngine {
4747
*/
4848
private readonly manifest = getAngularAppEngineManifest();
4949

50+
/**
51+
* A cache that holds entry points, keyed by their potential locale string.
52+
*/
53+
private readonly entryPointsCache = new Map<string, EntryPointExports>();
54+
5055
/**
5156
* Renders a response for the given HTTP request using the server application.
5257
*
@@ -65,12 +70,12 @@ export class AngularAppEngine {
6570
async render(request: Request, requestContext?: unknown): Promise<Response | null> {
6671
// Skip if the request looks like a file but not `/index.html`.
6772
const url = new URL(request.url);
68-
const entryPoint = this.getEntryPointFromUrl(url);
73+
const entryPoint = await this.getEntryPointExportsForUrl(url);
6974
if (!entryPoint) {
7075
return null;
7176
}
7277

73-
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = await entryPoint();
78+
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } = entryPoint;
7479
// Note: Using `instanceof` is not feasible here because `AngularServerApp` will
7580
// be located in separate bundles, making `instanceof` checks unreliable.
7681
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
@@ -80,28 +85,6 @@ export class AngularAppEngine {
8085
return serverApp.render(request, requestContext);
8186
}
8287

83-
/**
84-
* Retrieves the entry point path and locale for the Angular server application based on the provided URL.
85-
*
86-
* This method determines the appropriate entry point and locale for rendering the application by examining the URL.
87-
* If there is only one entry point available, it is returned regardless of the URL.
88-
* Otherwise, the method extracts a potential locale identifier from the URL and looks up the corresponding entry point.
89-
*
90-
* @param url - The URL used to derive the locale and determine the appropriate entry point.
91-
* @returns A function that returns a promise resolving to an object with the `EntryPointExports` type,
92-
* or `undefined` if no matching entry point is found for the extracted locale.
93-
*/
94-
private getEntryPointFromUrl(url: URL): (() => Promise<EntryPointExports>) | undefined {
95-
const { entryPoints, basePath } = this.manifest;
96-
if (entryPoints.size === 1) {
97-
return entryPoints.values().next().value;
98-
}
99-
100-
const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath);
101-
102-
return entryPoints.get(potentialLocale);
103-
}
104-
10588
/**
10689
* Retrieves HTTP headers for a request associated with statically generated (SSG) pages,
10790
* based on the URL pathname.
@@ -120,4 +103,52 @@ export class AngularAppEngine {
120103

121104
return new Map(headers);
122105
}
106+
107+
/**
108+
* Retrieves the exports for a specific entry point, caching the result.
109+
*
110+
* @param potentialLocale - The locale string used to find the corresponding entry point.
111+
* @returns A promise that resolves to the entry point exports or `undefined` if not found.
112+
*/
113+
private async getEntryPointExports(
114+
potentialLocale: string,
115+
): Promise<EntryPointExports | undefined> {
116+
const cachedEntryPoint = this.entryPointsCache.get(potentialLocale);
117+
if (cachedEntryPoint) {
118+
return cachedEntryPoint;
119+
}
120+
121+
const { entryPoints } = this.manifest;
122+
const entryPoint = entryPoints.get(potentialLocale);
123+
if (!entryPoint) {
124+
return undefined;
125+
}
126+
127+
const entryPointExports = await entryPoint();
128+
this.entryPointsCache.set(potentialLocale, entryPointExports);
129+
130+
return entryPointExports;
131+
}
132+
133+
/**
134+
* Retrieves the entry point for a given URL by determining the locale and mapping it to
135+
* the appropriate application bundle.
136+
*
137+
* This method determines the appropriate entry point and locale for rendering the application by examining the URL.
138+
* If there is only one entry point available, it is returned regardless of the URL.
139+
* Otherwise, the method extracts a potential locale identifier from the URL and looks up the corresponding entry point.
140+
*
141+
* @param url - The URL of the request.
142+
* @returns A promise that resolves to the entry point exports or `undefined` if not found.
143+
*/
144+
private getEntryPointExportsForUrl(url: URL): Promise<EntryPointExports | undefined> {
145+
const { entryPoints, basePath } = this.manifest;
146+
if (entryPoints.size === 1) {
147+
return this.getEntryPointExports('');
148+
}
149+
150+
const potentialLocale = getPotentialLocaleIdFromUrl(url, basePath);
151+
152+
return this.getEntryPointExports(potentialLocale);
153+
}
123154
}

0 commit comments

Comments
 (0)