From 562c472a124e4e8866e99ee0877c3d70b77bbf51 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Wed, 28 Aug 2024 05:55:05 +0000 Subject: [PATCH] refactor(@angular/ssr): Add Utility Function for route extraction and tree creation This commit introduces a new utility function designed to extract routes and creating a corresponding route tree. --- packages/angular/ssr/private_export.ts | 6 ++- packages/angular/ssr/src/routes/ng-routes.ts | 39 ++++++++++++++++++++ packages/angular/ssr/src/routes/router.ts | 30 +++------------ 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/packages/angular/ssr/private_export.ts b/packages/angular/ssr/private_export.ts index 9c5573471467..0cb5189adb3a 100644 --- a/packages/angular/ssr/private_export.ts +++ b/packages/angular/ssr/private_export.ts @@ -6,7 +6,11 @@ * found in the LICENSE file at https://angular.dev/license */ -export { getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig } from './src/routes/ng-routes'; +// ɵgetRoutesFromAngularRouterConfig is only used by the Webpack based server builder. +export { + getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig, + extractRoutesAndCreateRouteTree as ɵextractRoutesAndCreateRouteTree, +} from './src/routes/ng-routes'; export { ServerRenderContext as ɵServerRenderContext, getOrCreateAngularServerApp as ɵgetOrCreateAngularServerApp, diff --git a/packages/angular/ssr/src/routes/ng-routes.ts b/packages/angular/ssr/src/routes/ng-routes.ts index b140a5c989f9..3ead85923c82 100644 --- a/packages/angular/ssr/src/routes/ng-routes.ts +++ b/packages/angular/ssr/src/routes/ng-routes.ts @@ -22,9 +22,12 @@ import { ɵINTERNAL_SERVER_PLATFORM_PROVIDERS as INTERNAL_SERVER_PLATFORM_PROVIDERS, } from '@angular/platform-server'; import { Route, Router, ɵloadChildren as loadChildrenHelper } from '@angular/router'; +import { ServerAssets } from '../assets'; import { Console } from '../console'; +import { AngularAppManifest, getAngularAppManifest } from '../manifest'; import { AngularBootstrap, isNgModule } from '../utils/ng'; import { joinUrlParts } from '../utils/url'; +import { RouteTree } from './route-tree'; /** * Result of extracting routes from an Angular application. @@ -257,3 +260,39 @@ export async function getRoutesFromAngularRouterConfig( platformRef.destroy(); } } + +/** + * Asynchronously extracts routes from the Angular application configuration + * and creates a `RouteTree` to manage server-side routing. + * + * @param url - The URL for server-side rendering. The URL is used to configure `ServerPlatformLocation`. This configuration is crucial + * for ensuring that API requests for relative paths succeed, which is essential for accurate route extraction. + * See: + * - https://github.com/angular/angular/blob/d608b857c689d17a7ffa33bbb510301014d24a17/packages/platform-server/src/location.ts#L51 + * - https://github.com/angular/angular/blob/6882cc7d9eed26d3caeedca027452367ba25f2b9/packages/platform-server/src/http.ts#L44 + * @param manifest - An optional `AngularAppManifest` that contains the application's routing and configuration details. + * If not provided, the default manifest is retrieved using `getAngularAppManifest()`. + * + * @returns A promise that resolves to a populated `RouteTree` containing all extracted routes from the Angular application. + */ +export async function extractRoutesAndCreateRouteTree( + url: URL, + manifest: AngularAppManifest = getAngularAppManifest(), +): Promise { + const routeTree = new RouteTree(); + const document = await new ServerAssets(manifest).getIndexServerHtml(); + const { baseHref, routes } = await getRoutesFromAngularRouterConfig( + manifest.bootstrap(), + document, + url, + ); + + for (let { route, redirectTo } of routes) { + route = joinUrlParts(baseHref, route); + redirectTo = redirectTo === undefined ? undefined : joinUrlParts(baseHref, redirectTo); + + routeTree.insert(route, { redirectTo }); + } + + return routeTree; +} diff --git a/packages/angular/ssr/src/routes/router.ts b/packages/angular/ssr/src/routes/router.ts index 2361b874f6e7..b708356b331d 100644 --- a/packages/angular/ssr/src/routes/router.ts +++ b/packages/angular/ssr/src/routes/router.ts @@ -6,10 +6,9 @@ * found in the LICENSE file at https://angular.dev/license */ -import { ServerAssets } from '../assets'; import { AngularAppManifest } from '../manifest'; -import { joinUrlParts, stripIndexHtmlFromURL } from '../utils/url'; -import { getRoutesFromAngularRouterConfig } from './ng-routes'; +import { stripIndexHtmlFromURL } from '../utils/url'; +import { extractRoutesAndCreateRouteTree } from './ng-routes'; import { RouteTree, RouteTreeNodeMetadata } from './route-tree'; /** @@ -55,28 +54,11 @@ export class ServerRouter { // Create and store a new promise for the build process. // This prevents concurrent builds by re-using the same promise. - ServerRouter.#extractionPromise ??= (async () => { - try { - const routeTree = new RouteTree(); - const document = await new ServerAssets(manifest).getIndexServerHtml(); - const { baseHref, routes } = await getRoutesFromAngularRouterConfig( - manifest.bootstrap(), - document, - url, - ); - - for (let { route, redirectTo } of routes) { - route = joinUrlParts(baseHref, route); - redirectTo = redirectTo === undefined ? undefined : joinUrlParts(baseHref, redirectTo); - - routeTree.insert(route, { redirectTo }); - } - - return new ServerRouter(routeTree); - } finally { + ServerRouter.#extractionPromise ??= extractRoutesAndCreateRouteTree(url, manifest) + .then((routeTree) => new ServerRouter(routeTree)) + .finally(() => { ServerRouter.#extractionPromise = undefined; - } - })(); + }); return ServerRouter.#extractionPromise; }