From 09cac2e69bd77620f169bfe14c6cf6819ec572ab Mon Sep 17 00:00:00 2001 From: Alan Agius <17563226+alan-agius4@users.noreply.github.com> Date: Tue, 3 Mar 2026 13:40:14 +0000 Subject: [PATCH] fix(@angular/ssr): introduce DI token to signal route discovery process A new DI token, `IS_DISCOVERING_ROUTES`, is introduced to provide a clear signal for when the application is operating in route discovery mode. This token is provided with the value `true` within the route extraction providers. Other services and components can inject this token to conditionally alter their behavior, for instance, to disable functionality that is not required or could interfere with the route discovery process. Closes #32474 --- goldens/public-api/angular/ssr/index.api.md | 4 ++++ packages/angular/ssr/public_api.ts | 2 ++ packages/angular/ssr/src/routes/ng-routes.ts | 22 +++++++++++++++++ .../angular/ssr/test/routes/ng-routes_spec.ts | 24 ++++++++++++++++++- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/goldens/public-api/angular/ssr/index.api.md b/goldens/public-api/angular/ssr/index.api.md index e44a7099b521..e5d85138b72f 100644 --- a/goldens/public-api/angular/ssr/index.api.md +++ b/goldens/public-api/angular/ssr/index.api.md @@ -6,6 +6,7 @@ import { DefaultExport } from '@angular/router'; import { EnvironmentProviders } from '@angular/core'; +import { InjectionToken } from '@angular/core'; import { Provider } from '@angular/core'; import { Type } from '@angular/core'; @@ -26,6 +27,9 @@ export interface AngularAppEngineOptions { // @public export function createRequestHandler(handler: RequestHandlerFunction): RequestHandlerFunction; +// @public +export const IS_DISCOVERING_ROUTES: InjectionToken; + // @public export enum PrerenderFallback { Client = 1, diff --git a/packages/angular/ssr/public_api.ts b/packages/angular/ssr/public_api.ts index e566d8414f2f..eb05be266588 100644 --- a/packages/angular/ssr/public_api.ts +++ b/packages/angular/ssr/public_api.ts @@ -24,3 +24,5 @@ export { type ServerRouteServer, type ServerRouteCommon, } from './src/routes/route-config'; + +export { IS_DISCOVERING_ROUTES } from './src/routes/ng-routes'; diff --git a/packages/angular/ssr/src/routes/ng-routes.ts b/packages/angular/ssr/src/routes/ng-routes.ts index b60e704371a4..438e8450d331 100644 --- a/packages/angular/ssr/src/routes/ng-routes.ts +++ b/packages/angular/ssr/src/routes/ng-routes.ts @@ -11,6 +11,7 @@ import { ApplicationRef, Compiler, EnvironmentInjector, + InjectionToken, Injector, createEnvironmentInjector, runInInjectionContext, @@ -23,6 +24,7 @@ import { Router, ɵloadChildren as loadChildrenHelper, } from '@angular/router'; + import { ServerAssets } from '../assets'; import { Console } from '../console'; import { AngularAppManifest, getAngularAppManifest } from '../manifest'; @@ -39,6 +41,22 @@ import { } from './route-config'; import { RouteTree, RouteTreeNodeMetadata } from './route-tree'; +/** + * A DI token that indicates whether the application is in the process of discovering routes. + * + * This token is provided with the value `true` when route discovery is active, allowing other + * parts of the application to conditionally execute logic. For example, it can be used to + * disable features or behaviors that are not necessary or might interfere with the route + * discovery process. + */ +export const IS_DISCOVERING_ROUTES = new InjectionToken( + typeof ngDevMode === 'undefined' || ngDevMode ? 'IS_DISCOVERING_ROUTES' : '', + { + providedIn: 'platform', + factory: () => false, + }, +); + interface Route extends AngularRoute { ɵentryName?: string; } @@ -623,6 +641,10 @@ export async function getRoutesFromAngularRouterConfig( provide: ɵENABLE_ROOT_COMPONENT_BOOTSTRAP, useValue: false, }, + { + provide: IS_DISCOVERING_ROUTES, + useValue: true, + }, ]); try { diff --git a/packages/angular/ssr/test/routes/ng-routes_spec.ts b/packages/angular/ssr/test/routes/ng-routes_spec.ts index 324abe8c4d29..1532eb337faa 100644 --- a/packages/angular/ssr/test/routes/ng-routes_spec.ts +++ b/packages/angular/ssr/test/routes/ng-routes_spec.ts @@ -18,7 +18,7 @@ import { provideRouter, withEnabledBlockingInitialNavigation, } from '@angular/router'; -import { extractRoutesAndCreateRouteTree } from '../../src/routes/ng-routes'; +import { IS_DISCOVERING_ROUTES, extractRoutesAndCreateRouteTree } from '../../src/routes/ng-routes'; import { PrerenderFallback, RenderMode } from '../../src/routes/route-config'; import { setAngularAppTestingManifest } from '../testing-utils'; @@ -790,4 +790,26 @@ describe('extractRoutesAndCreateRouteTree', () => { { route: '/home', renderMode: RenderMode.Server }, ]); }); + + it('should provide `IS_DISCOVERING_ROUTES` as `true` during route discovery', async () => { + let isDiscoveringRoutes: boolean | undefined; + + setAngularAppTestingManifest( + [ + { + path: 'lazy', + loadChildren: () => { + isDiscoveringRoutes = inject(IS_DISCOVERING_ROUTES); + + return []; + }, + }, + ], + [{ path: '**', renderMode: RenderMode.Server }], + ); + + await extractRoutesAndCreateRouteTree({ url }); + + expect(isDiscoveringRoutes).toBeTrue(); + }); });