Skip to content

Commit 812355c

Browse files
JoostKjosephperrott
authored andcommitted
perf(core): do not recurse into modules that have already been registered (#39514)
When registering an NgModule based on its id, all transitively imported NgModules are also registered. This commit introduces a visited set to avoid traversing into NgModules that are reachable from multiple import paths multiple times. Fixes #39487 PR Close #39514
1 parent 71d0063 commit 812355c

File tree

2 files changed

+24
-16
lines changed

2 files changed

+24
-16
lines changed

packages/core/src/linker/ng_module_factory_registration.ts

+22-14
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88

99

1010
import {Type} from '../interface/type';
11-
import {autoRegisterModuleById} from '../render3/definition';
11+
import {autoRegisterModuleById, getNgModuleDef} from '../render3/definition';
1212
import {NgModuleType} from '../render3/ng_module_ref';
13+
import {maybeUnwrapFn} from '../render3/util/misc_utils';
1314
import {stringify} from '../util/stringify';
1415

1516
import {NgModuleFactory} from './ng_module_factory';
@@ -39,20 +40,27 @@ function assertSameOrNotExisting(id: string, type: Type<any>|null, incoming: Typ
3940
}
4041
}
4142

42-
export function registerNgModuleType(ngModuleType: NgModuleType) {
43-
if (ngModuleType.ɵmod.id !== null) {
44-
const id = ngModuleType.ɵmod.id;
45-
const existing = modules.get(id) as NgModuleType | null;
46-
assertSameOrNotExisting(id, existing, ngModuleType);
47-
modules.set(id, ngModuleType);
48-
}
43+
export function registerNgModuleType(ngModuleType: NgModuleType): void {
44+
const visited = new Set<NgModuleType>();
45+
recurse(ngModuleType);
46+
function recurse(ngModuleType: NgModuleType): void {
47+
// The imports array of an NgModule must refer to other NgModules,
48+
// so an error is thrown if no module definition is available.
49+
const def = getNgModuleDef(ngModuleType, /* throwNotFound */ true);
50+
const id = def.id;
51+
if (id !== null) {
52+
const existing = modules.get(id) as NgModuleType | null;
53+
assertSameOrNotExisting(id, existing, ngModuleType);
54+
modules.set(id, ngModuleType);
55+
}
4956

50-
let imports = ngModuleType.ɵmod.imports;
51-
if (imports instanceof Function) {
52-
imports = imports();
53-
}
54-
if (imports) {
55-
imports.forEach(i => registerNgModuleType(i as NgModuleType));
57+
const imports = maybeUnwrapFn(def.imports) as NgModuleType[];
58+
for (const i of imports) {
59+
if (!visited.has(i)) {
60+
visited.add(i);
61+
recurse(i);
62+
}
63+
}
5664
}
5765
}
5866

packages/core/test/render3/providers_spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Component as _Component, ComponentFactoryResolver, ElementRef, Injectable as _Injectable, InjectFlags, InjectionToken, InjectorType, Provider, RendererFactory2, Type, ViewContainerRef, ɵNgModuleDef as NgModuleDef, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵinject} from '../../src/core';
9+
import {Component as _Component, ComponentFactoryResolver, ElementRef, Injectable as _Injectable, InjectFlags, InjectionToken, InjectorType, Provider, RendererFactory2, Type, ViewContainerRef, ɵɵdefineInjectable, ɵɵdefineInjector, ɵɵdefineNgModule, ɵɵinject} from '../../src/core';
1010
import {forwardRef} from '../../src/di/forward_ref';
1111
import {createInjector} from '../../src/di/r3_injector';
1212
import {injectComponentFactoryResolver, ɵɵdefineComponent, ɵɵdefineDirective, ɵɵdirectiveInject, ɵɵelement, ɵɵelementEnd, ɵɵelementStart, ɵɵgetInheritedFactory, ɵɵProvidersFeature, ɵɵtext, ɵɵtextInterpolate1} from '../../src/render3/index';
@@ -1092,7 +1092,7 @@ describe('providers', () => {
10921092
{provide: String, useValue: 'From module injector'}
10931093
]
10941094
});
1095-
static ɵmod: NgModuleDef<any> = {bootstrap: []} as any;
1095+
static ɵmod = ɵɵdefineNgModule({type: MyAppModule});
10961096
}
10971097
const myAppModuleFactory = new NgModuleFactory(MyAppModule);
10981098
const ngModuleRef = myAppModuleFactory.create(null);

0 commit comments

Comments
 (0)