From 964487302301cddc218cce339a5c1b49d1dc3f70 Mon Sep 17 00:00:00 2001 From: Alex Rickabaugh Date: Tue, 10 Jul 2018 10:01:30 -0700 Subject: [PATCH] fix(ivy): ignore imports without ngInjectorDef in r3_injector (#24862) ngInjectorDef.imports is generated from @NgModule.imports plus @NgModule.exports. A problem arises as a result, because @NgModule exports contain not only other modules (which will have ngInjectorDef fields), but components, directives, and pipes as well. Because of locality, it's difficult for the compiler to filter these out at build time. It's not impossible, but for now filtering them out at runtime will allow testing of the compiler against complex applications. PR Close #24862 --- packages/core/src/di/r3_injector.ts | 11 ++++++++--- packages/core/test/di/r3_injector_spec.ts | 15 +++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index 28742c19a2..e8dcdf42ef 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -231,9 +231,9 @@ export class R3Injector { def = ngModule.ngInjectorDef; } - // If no definition was found, throw. + // If no definition was found, it might be from exports. Remove it. if (def == null) { - throw new Error(`Type ${stringify(defType)} is missing an ngInjectorDef definition.`); + return; } // Check for circular dependencies. @@ -333,7 +333,12 @@ export class R3Injector { function injectableDefRecord(token: Type| InjectionToken): Record { const def = (token as InjectableType).ngInjectableDef as InjectableDef; if (def === undefined) { - throw new Error(`Type ${stringify(token)} is missing an ngInjectableDef definition.`); + if (token instanceof InjectionToken) { + throw new Error(`Token ${stringify(token)} is missing an ngInjectableDef definition.`); + } + // TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a + // no-args constructor. + return makeRecord(() => new (token as Type)()); } return makeRecord(def.factory); } diff --git a/packages/core/test/di/r3_injector_spec.ts b/packages/core/test/di/r3_injector_spec.ts index 5e690b2f86..5f7a59124c 100644 --- a/packages/core/test/di/r3_injector_spec.ts +++ b/packages/core/test/di/r3_injector_spec.ts @@ -143,6 +143,16 @@ describe('InjectorDef-based createInjector()', () => { }); } + class NotAModule {} + + class ImportsNotAModule { + static ngInjectorDef = defineInjector({ + factory: () => new ImportsNotAModule(), + imports: [NotAModule], + providers: [], + }); + } + class ScopedService { static ngInjectableDef = defineInjectable({ providedIn: Module, @@ -241,4 +251,9 @@ describe('InjectorDef-based createInjector()', () => { expect(() => (injector as R3Injector).destroy()) .toThrowError('Injector has already been destroyed.'); }); + + it('should not crash when importing something that has no ngInjectorDef', () => { + injector = createInjector(ImportsNotAModule); + expect(injector.get(ImportsNotAModule)).toBeDefined(); + }); });