From 660444fbf296ce45f0a33d443e804237fa9bb8cc Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 8 Aug 2025 10:45:43 +0200 Subject: [PATCH] fix(router): attempt to resolve component resources in JIT mode (#63062) In #62758 we started loading the component resources during bootstrap in JIT mode to ensure that they're in place by the time we create the component. This won't work for lazy-loaded components in the router, because they don't exist at bootstrap time. These changes add similar logic when the router loads a component. PR Close #63062 --- .../router/bundle.golden_symbols.json | 1 + packages/router/src/router_config_loader.ts | 21 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index 4e0cfebd47d..a245562b1b1 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -903,6 +903,7 @@ "matchWithChecks", "materializeViewResults", "matrixParamsMatch", + "maybeResolveResources", "maybeReturnReactiveLViewConsumer", "maybeSchedule", "maybeUnwrapDefaultExport", diff --git a/packages/router/src/router_config_loader.ts b/packages/router/src/router_config_loader.ts index 604c3b5aa70..0d948408765 100644 --- a/packages/router/src/router_config_loader.ts +++ b/packages/router/src/router_config_loader.ts @@ -16,9 +16,10 @@ import { NgModuleFactory, runInInjectionContext, Type, + ɵresolveComponentResources as resolveComponentResources, } from '@angular/core'; import {ConnectableObservable, from, Observable, of, Subject} from 'rxjs'; -import {finalize, map, mergeMap, refCount, tap} from 'rxjs/operators'; +import {finalize, map, mergeMap, refCount, switchMap, tap} from 'rxjs/operators'; import {DefaultExport, LoadedRouterConfig, Route, Routes} from './models'; import {wrapIntoObservable} from './utils/collection'; @@ -61,6 +62,7 @@ export class RouterConfigLoader { runInInjectionContext(injector, () => route.loadComponent!()), ).pipe( map(maybeUnwrapDefaultExport), + switchMap(maybeResolveResources), tap((component) => { if (this.onLoadEndListener) { this.onLoadEndListener(route); @@ -130,6 +132,7 @@ export function loadChildren( runInInjectionContext(parentInjector, () => route.loadChildren!()), ).pipe( map(maybeUnwrapDefaultExport), + switchMap(maybeResolveResources), mergeMap((t) => { if (t instanceof NgModuleFactory || Array.isArray(t)) { return of(t); @@ -177,3 +180,19 @@ function maybeUnwrapDefaultExport(input: T | DefaultExport): T { // subject to property renaming, so we reference it with bracket access. return isWrappedDefaultExport(input) ? input['default'] : input; } + +function maybeResolveResources(value: T): Promise | Observable { + // In JIT mode we usually resolve the resources of components on bootstrap, however + // that won't have happened for lazy-loaded components. Attempt to load any pending + // resources again here. + if ((typeof ngJitMode === 'undefined' || ngJitMode) && typeof fetch === 'function') { + return resolveComponentResources(fetch) + .catch((error) => { + console.error(error); + return Promise.resolve(); + }) + .then(() => value); + } + + return of(value); +}