Skip to content

Commit 21b5852

Browse files
alan-agius4josephperrott
authored andcommitted
fix(@angular/ssr): ensure loadChildren runs in correct injection context during route extraction
Ensure that `loadChildren` functions are executed within the route’s specific injection context when extracting routes, aligning behavior with Angular’s dependency injection model. More context: angular/angular#62133 Closes #29483
1 parent dc45c18 commit 21b5852

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import { APP_BASE_HREF, PlatformLocation } from '@angular/common';
1010
import {
1111
ApplicationRef,
1212
Compiler,
13+
EnvironmentInjector,
1314
Injector,
15+
createEnvironmentInjector,
1416
runInInjectionContext,
1517
ɵConsole,
1618
ɵENABLE_ROOT_COMPONENT_BOOTSTRAP,
@@ -195,14 +197,22 @@ async function* handleRoute(options: {
195197
appendPreloadToMetadata(ɵentryName, entryPointToBrowserMapping, metadata);
196198
}
197199

200+
const routeInjector = route.providers
201+
? createEnvironmentInjector(
202+
route.providers,
203+
parentInjector.get(EnvironmentInjector),
204+
`Route: ${route.path}`,
205+
)
206+
: parentInjector;
207+
198208
const loadedChildRoutes = await loadChildrenHelper(
199209
route,
200210
compiler,
201-
parentInjector,
211+
routeInjector,
202212
).toPromise();
203213

204214
if (loadedChildRoutes) {
205-
const { routes: childRoutes, injector = parentInjector } = loadedChildRoutes;
215+
const { routes: childRoutes, injector = routeInjector } = loadedChildRoutes;
206216
yield* traverseRoutesConfig({
207217
...options,
208218
routes: childRoutes,

packages/angular/ssr/test/routes/ng-routes_spec.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,13 @@
1111
import '@angular/compiler';
1212
/* eslint-enable import/no-unassigned-import */
1313

14-
import { Component } from '@angular/core';
15-
import { Routes, provideRouter, withEnabledBlockingInitialNavigation } from '@angular/router';
14+
import { Component, InjectionToken, Injector, inject } from '@angular/core';
15+
import {
16+
Route,
17+
Routes,
18+
provideRouter,
19+
withEnabledBlockingInitialNavigation,
20+
} from '@angular/router';
1621
import { extractRoutesAndCreateRouteTree } from '../../src/routes/ng-routes';
1722
import { PrerenderFallback, RenderMode } from '../../src/routes/route-config';
1823
import { setAngularAppTestingManifest } from '../testing-utils';
@@ -717,4 +722,36 @@ describe('extractRoutesAndCreateRouteTree', () => {
717722
{ route: '/**', renderMode: RenderMode.Server },
718723
]);
719724
});
725+
726+
it(`should create and run route level injector when 'loadChildren' is used`, async () => {
727+
const ChildRoutes = new InjectionToken<Route[]>('Child Routes');
728+
setAngularAppTestingManifest(
729+
[
730+
{
731+
path: '',
732+
component: DummyComponent,
733+
providers: [
734+
{
735+
provide: ChildRoutes,
736+
useValue: [
737+
{
738+
path: 'home',
739+
component: DummyComponent,
740+
},
741+
],
742+
},
743+
],
744+
loadChildren: () => inject(ChildRoutes),
745+
},
746+
],
747+
[{ path: '**', renderMode: RenderMode.Server }],
748+
);
749+
750+
const { routeTree, errors } = await extractRoutesAndCreateRouteTree({ url });
751+
expect(errors).toHaveSize(0);
752+
expect(routeTree.toObject()).toEqual([
753+
{ route: '/', renderMode: RenderMode.Server },
754+
{ route: '/home', renderMode: RenderMode.Server },
755+
]);
756+
});
720757
});

0 commit comments

Comments
 (0)