Skip to content

Commit 9fa75a8

Browse files
committed
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.
1 parent 6df7578 commit 9fa75a8

File tree

3 files changed

+50
-25
lines changed

3 files changed

+50
-25
lines changed

packages/angular/ssr/private_export.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
export { getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig } from './src/routes/ng-routes';
9+
// ɵgetRoutesFromAngularRouterConfig is only used by the Webpack based server builder.
10+
export {
11+
getRoutesFromAngularRouterConfig as ɵgetRoutesFromAngularRouterConfig,
12+
extractRoutesAndCreateRouteTree as ɵextractRoutesAndCreateRouteTree,
13+
} from './src/routes/ng-routes';
1014
export {
1115
ServerRenderContext as ɵServerRenderContext,
1216
getOrCreateAngularServerApp as ɵgetOrCreateAngularServerApp,

packages/angular/ssr/src/routes/ng-routes.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@ import {
2222
ɵINTERNAL_SERVER_PLATFORM_PROVIDERS as INTERNAL_SERVER_PLATFORM_PROVIDERS,
2323
} from '@angular/platform-server';
2424
import { Route, Router, ɵloadChildren as loadChildrenHelper } from '@angular/router';
25+
import { ServerAssets } from '../assets';
2526
import { Console } from '../console';
27+
import { AngularAppManifest, getAngularAppManifest } from '../manifest';
2628
import { AngularBootstrap, isNgModule } from '../utils/ng';
2729
import { joinUrlParts } from '../utils/url';
30+
import { RouteTree } from './route-tree';
2831

2932
/**
3033
* Result of extracting routes from an Angular application.
@@ -257,3 +260,39 @@ export async function getRoutesFromAngularRouterConfig(
257260
platformRef.destroy();
258261
}
259262
}
263+
264+
/**
265+
* Asynchronously extracts routes from the Angular application configuration
266+
* and creates a `RouteTree` to manage server-side routing.
267+
*
268+
* @param url - The URL for server-side rendering. The URL is used to configure `ServerPlatformLocation`. This configuration is crucial
269+
* for ensuring that API requests for relative paths succeed, which is essential for accurate route extraction.
270+
* See:
271+
* - https://github.com/angular/angular/blob/d608b857c689d17a7ffa33bbb510301014d24a17/packages/platform-server/src/location.ts#L51
272+
* - https://github.com/angular/angular/blob/6882cc7d9eed26d3caeedca027452367ba25f2b9/packages/platform-server/src/http.ts#L44
273+
* @param manifest - An optional `AngularAppManifest` that contains the application's routing and configuration details.
274+
* If not provided, the default manifest is retrieved using `getAngularAppManifest()`.
275+
*
276+
* @returns A promise that resolves to a populated `RouteTree` containing all extracted routes from the Angular application.
277+
*/
278+
export async function extractRoutesAndCreateRouteTree(
279+
url: URL,
280+
manifest: AngularAppManifest = getAngularAppManifest(),
281+
): Promise<RouteTree> {
282+
const routeTree = new RouteTree();
283+
const document = await new ServerAssets(manifest).getIndexServerHtml();
284+
const { baseHref, routes } = await getRoutesFromAngularRouterConfig(
285+
manifest.bootstrap(),
286+
document,
287+
url,
288+
);
289+
290+
for (let { route, redirectTo } of routes) {
291+
route = joinUrlParts(baseHref, route);
292+
redirectTo = redirectTo === undefined ? undefined : joinUrlParts(baseHref, redirectTo);
293+
294+
routeTree.insert(route, { redirectTo });
295+
}
296+
297+
return routeTree;
298+
}

packages/angular/ssr/src/routes/router.ts

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9-
import { ServerAssets } from '../assets';
109
import { AngularAppManifest } from '../manifest';
11-
import { joinUrlParts, stripIndexHtmlFromURL } from '../utils/url';
12-
import { getRoutesFromAngularRouterConfig } from './ng-routes';
10+
import { stripIndexHtmlFromURL } from '../utils/url';
11+
import { extractRoutesAndCreateRouteTree } from './ng-routes';
1312
import { RouteTree, RouteTreeNodeMetadata } from './route-tree';
1413

1514
/**
@@ -55,28 +54,11 @@ export class ServerRouter {
5554

5655
// Create and store a new promise for the build process.
5756
// This prevents concurrent builds by re-using the same promise.
58-
ServerRouter.#extractionPromise ??= (async () => {
59-
try {
60-
const routeTree = new RouteTree();
61-
const document = await new ServerAssets(manifest).getIndexServerHtml();
62-
const { baseHref, routes } = await getRoutesFromAngularRouterConfig(
63-
manifest.bootstrap(),
64-
document,
65-
url,
66-
);
67-
68-
for (let { route, redirectTo } of routes) {
69-
route = joinUrlParts(baseHref, route);
70-
redirectTo = redirectTo === undefined ? undefined : joinUrlParts(baseHref, redirectTo);
71-
72-
routeTree.insert(route, { redirectTo });
73-
}
74-
75-
return new ServerRouter(routeTree);
76-
} finally {
57+
ServerRouter.#extractionPromise ??= extractRoutesAndCreateRouteTree(url, manifest)
58+
.then((routeTree) => new ServerRouter(routeTree))
59+
.finally(() => {
7760
ServerRouter.#extractionPromise = undefined;
78-
}
79-
})();
61+
});
8062

8163
return ServerRouter.#extractionPromise;
8264
}

0 commit comments

Comments
 (0)