Skip to content

Commit

Permalink
refactor(@angular/ssr): remove duplicate code and streamline function…
Browse files Browse the repository at this point in the history
…ality

This commit cleans up duplicate code left from the previous implementations of process, serve, and render. Additionally, prerender serve now exclusively handles HEAD and GET requests, aligning with updated handling requirements. The private `renderStatic` method has been removed in favor of the `handle` method for improved maintainability.

(cherry picked from commit e16cbb9)
  • Loading branch information
alan-agius4 committed Nov 6, 2024
1 parent 1e37b59 commit e04b891
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 217 deletions.
1 change: 1 addition & 0 deletions goldens/public-api/angular/ssr/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { EnvironmentProviders } from '@angular/core';
// @public
export class AngularAppEngine {
handle(request: Request, requestContext?: unknown): Promise<Response | null>;
static ɵallowStaticRouteRender: boolean;
static ɵhooks: Hooks;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ export function createAngularSsrInternalMiddleware(
ɵgetOrCreateAngularServerApp: typeof getOrCreateAngularServerApp;
};

const angularServerApp = ɵgetOrCreateAngularServerApp();
const angularServerApp = ɵgetOrCreateAngularServerApp({
allowStaticRouteRender: true,
});

// Only Add the transform hook only if it's a different instance.
if (cachedAngularServerApp !== angularServerApp) {
angularServerApp.hooks.on('html:transform:pre', async ({ html, url }) => {
Expand Down Expand Up @@ -96,6 +99,7 @@ export async function createAngularSsrExternalMiddleware(
reqHandler?: unknown;
AngularAppEngine: typeof SSRAngularAppEngine;
};

if (!isSsrNodeRequestHandler(reqHandler) && !isSsrRequestHandler(reqHandler)) {
if (!fallbackWarningShown) {
// eslint-disable-next-line no-console
Expand All @@ -118,6 +122,7 @@ export async function createAngularSsrExternalMiddleware(
}

if (cachedAngularAppEngine !== AngularAppEngine) {
AngularAppEngine.ɵallowStaticRouteRender = true;
AngularAppEngine.ɵhooks.on('html:transform:pre', async ({ html, url }) => {
const processedHtml = await server.transformIndexHtml(url.pathname, html);

Expand Down
16 changes: 15 additions & 1 deletion packages/angular/build/src/utils/server-rendering/prerender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ async function getAllRoutes(

if (appShellOptions) {
routes.push({
renderMode: RouteRenderMode.AppShell,
route: urlJoin(baseHref, appShellOptions.route),
});
}
Expand All @@ -288,6 +289,7 @@ async function getAllRoutes(
const routesFromFile = (await readFile(routesFile, 'utf8')).split(/\r?\n/);
for (const route of routesFromFile) {
routes.push({
renderMode: RouteRenderMode.Prerender,
route: urlJoin(baseHref, route.trim()),
});
}
Expand Down Expand Up @@ -321,7 +323,19 @@ async function getAllRoutes(
{},
);

return { errors, serializedRouteTree: [...routes, ...serializedRouteTree] };
if (!routes.length) {
return { errors, serializedRouteTree };
}

// Merge the routing trees
const uniqueRoutes = new Map();
for (const item of [...routes, ...serializedRouteTree]) {
if (!uniqueRoutes.has(item.route)) {
uniqueRoutes.set(item.route, item);
}
}

return { errors, serializedRouteTree: Array.from(uniqueRoutes.values()) };
} catch (err) {
assertIsError(err);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@ let serverURL = DEFAULT_URL;
async function renderPage({ url }: RenderOptions): Promise<string | null> {
const { ɵgetOrCreateAngularServerApp: getOrCreateAngularServerApp } =
await loadEsmModuleFromMemory('./main.server.mjs');
const angularServerApp = getOrCreateAngularServerApp();
const response = await angularServerApp.renderStatic(
new URL(url, serverURL),
AbortSignal.timeout(30_000),

const angularServerApp = getOrCreateAngularServerApp({
allowStaticRouteRender: true,
});

const response = await angularServerApp.handle(
new Request(new URL(url, serverURL), { signal: AbortSignal.timeout(30_000) }),
);

return response ? response.text() : null;
Expand Down
34 changes: 18 additions & 16 deletions packages/angular/ssr/src/app-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
* found in the LICENSE file at https://angular.dev/license
*/

import type { AngularServerApp } from './app';
import type { AngularServerApp, getOrCreateAngularServerApp } from './app';
import { Hooks } from './hooks';
import { getPotentialLocaleIdFromUrl } from './i18n';
import { EntryPointExports, getAngularAppEngineManifest } from './manifest';
import { stripIndexHtmlFromURL, stripTrailingSlash } from './utils/url';

/**
* Angular server application engine.
Expand All @@ -24,23 +23,23 @@ import { stripIndexHtmlFromURL, stripTrailingSlash } from './utils/url';
*/
export class AngularAppEngine {
/**
* Hooks for extending or modifying the behavior of the server application.
* These hooks are used by the Angular CLI when running the development server and
* provide extensibility points for the application lifecycle.
* A flag to enable or disable the rendering of prerendered routes.
*
* Typically used during development to avoid prerendering all routes ahead of time,
* allowing them to be rendered on the fly as requested.
*
* @private
*/
static ɵhooks = /* #__PURE__*/ new Hooks();
static ɵallowStaticRouteRender = false;

/**
* Provides access to the hooks for extending or modifying the server application's behavior.
* This allows attaching custom functionality to various server application lifecycle events.
* Hooks for extending or modifying the behavior of the server application.
* These hooks are used by the Angular CLI when running the development server and
* provide extensibility points for the application lifecycle.
*
* @internal
* @private
*/
get hooks(): Hooks {
return AngularAppEngine.ɵhooks;
}
static ɵhooks = /* #__PURE__*/ new Hooks();

/**
* The manifest for the server application.
Expand Down Expand Up @@ -88,12 +87,15 @@ export class AngularAppEngine {
return null;
}

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
const serverApp = getOrCreateAngularServerApp() as AngularServerApp;
serverApp.hooks = this.hooks;
const ɵgetOrCreateAngularServerApp =
entryPoint.ɵgetOrCreateAngularServerApp as typeof getOrCreateAngularServerApp;

const serverApp = ɵgetOrCreateAngularServerApp({
allowStaticRouteRender: AngularAppEngine.ɵallowStaticRouteRender,
hooks: AngularAppEngine.ɵhooks,
});

return serverApp;
}
Expand Down
Loading

0 comments on commit e04b891

Please sign in to comment.