From 7d6f4885b25f36ab5262d868b0a4d762dea27a62 Mon Sep 17 00:00:00 2001 From: Kara Erickson Date: Tue, 30 Apr 2019 20:24:00 -0700 Subject: [PATCH] fix(ivy): properly tree-shake away StaticInjector (#30219) Ivy uses R3Injector, but we are currently pulling in both the StaticInjector (View Engine injector) and the R3Injector when running with Ivy. This commit adds an ivy switch so calling Injector.create() pulls in the correct implementation of the injector depending on whether you are using VE or Ivy. This saves us about 3KB in the bundle. PR Close #30219 --- integration/_payload-limits.json | 2 +- .../core/src/core_render3_private_export.ts | 2 + packages/core/src/di/index.ts | 4 +- packages/core/src/di/injector.ts | 89 ++++--------------- .../core/src/di/injector_compatibility.ts | 76 ++++++++++++++++ packages/core/src/di/r3_injector.ts | 39 ++++---- packages/core/src/di/reflective_injector.ts | 3 +- packages/core/src/render3/errors.ts | 21 +++++ packages/core/src/render3/ng_module_ref.ts | 3 +- packages/core/src/view/ng_module.ts | 4 +- packages/core/src/view/util.ts | 2 +- .../injection/bundle.golden_symbols.json | 49 ++-------- packages/core/test/di/static_injector_spec.ts | 12 ++- packages/core/test/view/ng_module_spec.ts | 3 +- .../test/browser/bootstrap_spec.ts | 5 +- 15 files changed, 167 insertions(+), 147 deletions(-) diff --git a/integration/_payload-limits.json b/integration/_payload-limits.json index 65ba667766..edcb9b1800 100644 --- a/integration/_payload-limits.json +++ b/integration/_payload-limits.json @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime": 1440, - "main": 149205, + "main": 146225, "polyfills": 43567 } } diff --git a/packages/core/src/core_render3_private_export.ts b/packages/core/src/core_render3_private_export.ts index fad9dd161f..422e7dcc74 100644 --- a/packages/core/src/core_render3_private_export.ts +++ b/packages/core/src/core_render3_private_export.ts @@ -291,4 +291,6 @@ export { export {createInjector as ɵcreateInjector} from './di/r3_injector'; +export {INJECTOR_IMPL__POST_R3__ as ɵINJECTOR_IMPL__POST_R3__} from './di/injector'; + // clang-format on diff --git a/packages/core/src/di/index.ts b/packages/core/src/di/index.ts index 3c098f3306..6435213cad 100644 --- a/packages/core/src/di/index.ts +++ b/packages/core/src/di/index.ts @@ -17,8 +17,8 @@ export {InjectFlags} from './interface/injector'; export {ɵɵdefineInjectable, defineInjectable, ɵɵdefineInjector, InjectableType, InjectorType} from './interface/defs'; export {forwardRef, resolveForwardRef, ForwardRefFn} from './forward_ref'; export {Injectable, InjectableDecorator, InjectableProvider} from './injectable'; -export {INJECTOR, Injector} from './injector'; -export {ɵɵinject, inject} from './injector_compatibility'; +export {Injector} from './injector'; +export {ɵɵinject, inject, INJECTOR} from './injector_compatibility'; export {ReflectiveInjector} from './reflective_injector'; export {StaticProvider, ValueProvider, ConstructorSansProvider, ExistingProvider, FactoryProvider, Provider, TypeProvider, ClassProvider} from './interface/provider'; export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './reflective_provider'; diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index bc7ab65bde..bac0d1fe20 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -7,48 +7,29 @@ */ import {Type} from '../interface/type'; -import {getClosureSafeProperty} from '../util/property'; import {stringify} from '../util/stringify'; + import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {ɵɵinject} from './injector_compatibility'; +import {INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, formatError, ɵɵinject} from './injector_compatibility'; import {ɵɵdefineInjectable} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; +import {createInjector} from './r3_injector'; -export const SOURCE = '__source'; -const _THROW_IF_NOT_FOUND = new Object(); -export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; - -/** - * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. - * - * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a - * project. - * - * @publicApi - */ -export const INJECTOR = new InjectionToken( - 'INJECTOR', - -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. - ); - -export class NullInjector implements Injector { - get(token: any, notFoundValue: any = _THROW_IF_NOT_FOUND): any { - if (notFoundValue === _THROW_IF_NOT_FOUND) { - // Intentionally left behind: With dev tools open the debugger will stop here. There is no - // reason why correctly written application should cause this exception. - // TODO(misko): uncomment the next line once `ngDevMode` works with closure. - // if(ngDevMode) debugger; - const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); - error.name = 'NullInjectorError'; - throw error; - } - return notFoundValue; - } +export function INJECTOR_IMPL__PRE_R3__( + providers: StaticProvider[], parent: Injector | undefined, name: string) { + return new StaticInjector(providers, parent, name); } +export function INJECTOR_IMPL__POST_R3__( + providers: StaticProvider[], parent: Injector | undefined, name: string) { + return createInjector({name: name}, parent, providers, name); +} + +export const INJECTOR_IMPL = INJECTOR_IMPL__PRE_R3__; + /** * Concrete injectors implement this interface. * @@ -66,7 +47,7 @@ export class NullInjector implements Injector { * @publicApi */ export abstract class Injector { - static THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; + static THROW_IF_NOT_FOUND = THROW_IF_NOT_FOUND; static NULL: Injector = new NullInjector(); /** @@ -100,9 +81,9 @@ export abstract class Injector { options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string}, parent?: Injector): Injector { if (Array.isArray(options)) { - return new StaticInjector(options, parent); + return INJECTOR_IMPL(options, parent, ''); } else { - return new StaticInjector(options.providers, options.parent, options.name || null); + return INJECTOR_IMPL(options.providers, options.parent, options.name || ''); } } @@ -129,10 +110,7 @@ const CIRCULAR = IDENT; const MULTI_PROVIDER_FN = function(): any[] { return Array.prototype.slice.call(arguments); }; -export const USE_VALUE = - getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); -const NG_TOKEN_PATH = 'ngTokenPath'; -export const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; + const enum OptionFlags { Optional = 1 << 0, CheckSelf = 1 << 1, @@ -140,7 +118,6 @@ const enum OptionFlags { Default = CheckSelf | CheckParent } const NULL_INJECTOR = Injector.NULL; -const NEW_LINE = /\n/gm; const NO_NEW_LINE = 'ɵ'; export class StaticInjector implements Injector { @@ -377,38 +354,6 @@ function computeDeps(provider: StaticProvider): DependencyRecord[] { return deps; } -export function catchInjectorError( - e: any, token: any, injectorErrorName: string, source: string | null): never { - const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; - if (token[SOURCE]) { - tokenPath.unshift(token[SOURCE]); - } - e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); - e[NG_TOKEN_PATH] = tokenPath; - e[NG_TEMP_TOKEN_PATH] = null; - throw e; -} - -function formatError( - text: string, obj: any, injectorErrorName: string, source: string | null = null): string { - text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; - let context = stringify(obj); - if (obj instanceof Array) { - context = obj.map(stringify).join(' -> '); - } else if (typeof obj === 'object') { - let parts = []; - for (let key in obj) { - if (obj.hasOwnProperty(key)) { - let value = obj[key]; - parts.push( - key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value))); - } - } - context = `{${parts.join(', ')}}`; - } - return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; -} - function staticError(text: string, obj: any): Error { return new Error(formatError(text, obj, 'StaticInjectorError')); } diff --git a/packages/core/src/di/injector_compatibility.ts b/packages/core/src/di/injector_compatibility.ts index 423289a5d2..83cc2638ab 100644 --- a/packages/core/src/di/injector_compatibility.ts +++ b/packages/core/src/di/injector_compatibility.ts @@ -7,6 +7,7 @@ */ import {Type} from '../interface/type'; +import {getClosureSafeProperty} from '../util/property'; import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; @@ -14,10 +15,36 @@ import {InjectionToken} from './injection_token'; import {Injector} from './injector'; import {getInjectableDef, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; +import {ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; +/** + * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. + * + * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a + * project. + * + * @publicApi + */ +export const INJECTOR = new InjectionToken( + 'INJECTOR', + -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. + ); + +const _THROW_IF_NOT_FOUND = new Object(); +export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; + +export const NG_TEMP_TOKEN_PATH = 'ngTempTokenPath'; +const NG_TOKEN_PATH = 'ngTokenPath'; +const NEW_LINE = /\n/gm; +const NO_NEW_LINE = 'ɵ'; +export const SOURCE = '__source'; + +export const USE_VALUE = + getClosureSafeProperty({provide: String, useValue: getClosureSafeProperty}); + /** * Current injector value used by `inject`. * - `undefined`: it is an error to call `inject` @@ -166,3 +193,52 @@ export function injectArgs(types: (Type| InjectionToken| any[])[]): an } return args; } + + +export class NullInjector implements Injector { + get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any { + if (notFoundValue === THROW_IF_NOT_FOUND) { + // Intentionally left behind: With dev tools open the debugger will stop here. There is no + // reason why correctly written application should cause this exception. + // TODO(misko): uncomment the next line once `ngDevMode` works with closure. + // if(ngDevMode) debugger; + const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); + error.name = 'NullInjectorError'; + throw error; + } + return notFoundValue; + } +} + + +export function catchInjectorError( + e: any, token: any, injectorErrorName: string, source: string | null): never { + const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; + if (token[SOURCE]) { + tokenPath.unshift(token[SOURCE]); + } + e.message = formatError('\n' + e.message, tokenPath, injectorErrorName, source); + e[NG_TOKEN_PATH] = tokenPath; + e[NG_TEMP_TOKEN_PATH] = null; + throw e; +} + +export function formatError( + text: string, obj: any, injectorErrorName: string, source: string | null = null): string { + text = text && text.charAt(0) === '\n' && text.charAt(1) == NO_NEW_LINE ? text.substr(2) : text; + let context = stringify(obj); + if (obj instanceof Array) { + context = obj.map(stringify).join(' -> '); + } else if (typeof obj === 'object') { + let parts = []; + for (let key in obj) { + if (obj.hasOwnProperty(key)) { + let value = obj[key]; + parts.push( + key + ':' + (typeof value === 'string' ? JSON.stringify(value) : stringify(value))); + } + } + context = `{${parts.join(', ')}}`; + } + return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace(NEW_LINE, '\n ')}`; +} diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index 9532e23741..670c9902c5 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -8,12 +8,13 @@ import {OnDestroy} from '../interface/lifecycle_hooks'; import {Type} from '../interface/type'; +import {throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiProviderError} from '../render3/errors'; import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {INJECTOR, Injector, NG_TEMP_TOKEN_PATH, NullInjector, USE_VALUE, catchInjectorError} from './injector'; -import {injectArgs, setCurrentInjector, ɵɵinject} from './injector_compatibility'; +import {Injector} from './injector'; +import {INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, THROW_IF_NOT_FOUND, USE_VALUE, catchInjectorError, injectArgs, setCurrentInjector, ɵɵinject} from './injector_compatibility'; import {InjectableType, InjectorType, InjectorTypeWithProviders, getInjectableDef, getInjectorDef, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './interface/provider'; @@ -131,7 +132,7 @@ export class R3Injector { this.injectorDefTypes.forEach(defType => this.get(defType)); // Source name, used for debugging - this.source = source || (def instanceof Array ? null : stringify(def)); + this.source = source || (typeof def === 'object' ? null : stringify(def)); } /** @@ -157,7 +158,7 @@ export class R3Injector { } get( - token: Type|InjectionToken, notFoundValue: any = Injector.THROW_IF_NOT_FOUND, + token: Type|InjectionToken, notFoundValue: any = THROW_IF_NOT_FOUND, flags = InjectFlags.Default): T { this.assertNotDestroyed(); // Set the injection context. @@ -208,6 +209,12 @@ export class R3Injector { } } + toString() { + const tokens = [], records = this.records; + records.forEach((v, token) => tokens.push(stringify(token))); + return `R3Injector[${tokens.join(', ')}]`; + } + private assertNotDestroyed(): void { if (this._destroyed) { throw new Error('Injector has already been destroyed.'); @@ -242,7 +249,8 @@ export class R3Injector { (ngModule === undefined) ? (defOrWrappedDef as InjectorType) : ngModule; // Check for circular dependencies. - if (ngDevMode && parents.indexOf(defType) !== -1) { + // TODO(FW-1307): Re-add ngDevMode when closure can handle it + if (parents.indexOf(defType) !== -1) { const defName = stringify(defType); throw new Error( `Circular dependency in DI detected for type ${defName}. Dependency path: ${parents.map(defType => stringify(defType)).join(' > ')} > ${defName}.`); @@ -278,7 +286,8 @@ export class R3Injector { if (def.imports != null && !isDuplicate) { // Before processing defType's imports, add it to the set of parents. This way, if it ends // up deeply importing itself, this can be detected. - ngDevMode && parents.push(defType); + // TODO(FW-1307): Re-add ngDevMode when closure can handle it + parents.push(defType); // Add it to the set of dedups. This way we can detect multiple imports of the same module dedupStack.push(defType); @@ -287,7 +296,8 @@ export class R3Injector { def.imports, imported => this.processInjectorType(imported, parents, dedupStack)); } finally { // Remove it from the parents set when finished. - ngDevMode && parents.pop(); + // TODO(FW-1307): Re-add ngDevMode when closure can handle it + parents.pop(); } } @@ -325,7 +335,7 @@ export class R3Injector { if (multiRecord) { // It has. Throw a nice error if if (multiRecord.multi === undefined) { - throw new Error(`Mixed multi-provider for ${token}.`); + throwMixedMultiProviderError(); } } else { multiRecord = makeRecord(undefined, NOT_YET, true); @@ -337,7 +347,7 @@ export class R3Injector { } else { const existing = this.records.get(token); if (existing && existing.multi !== undefined) { - throw new Error(`Mixed multi-provider for ${stringify(token)}`); + throwMixedMultiProviderError(); } } this.records.set(token, record); @@ -345,7 +355,7 @@ export class R3Injector { private hydrate(token: Type|InjectionToken, record: Record): T { if (record.value === CIRCULAR) { - throw new Error(`Cannot instantiate cyclic dependency! ${stringify(token)}`); + throwCyclicDependencyError(stringify(token)); } else if (record.value === NOT_YET) { record.value = CIRCULAR; record.value = record.factory !(); @@ -421,14 +431,7 @@ export function providerToFactory( provider && ((provider as StaticClassProvider | ClassProvider).useClass || provider.provide)); if (!classRef) { - let ngModuleDetail = ''; - if (ngModuleType && providers) { - const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...'); - ngModuleDetail = - ` - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`; - } - throw new Error( - `Invalid provider for the NgModule '${stringify(ngModuleType)}'` + ngModuleDetail); + throwInvalidProviderError(ngModuleType, providers, provider); } if (hasDeps(provider)) { factory = () => new (classRef)(...injectArgs(provider.deps)); diff --git a/packages/core/src/di/reflective_injector.ts b/packages/core/src/di/reflective_injector.ts index 8ce87b226f..20ba0c39cf 100644 --- a/packages/core/src/di/reflective_injector.ts +++ b/packages/core/src/di/reflective_injector.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {Injector, THROW_IF_NOT_FOUND} from './injector'; +import {Injector} from './injector'; +import {THROW_IF_NOT_FOUND} from './injector_compatibility'; import {Provider} from './interface/provider'; import {Self, SkipSelf} from './metadata'; import {cyclicDependencyError, instantiationError, noProviderError, outOfBoundsError} from './reflective_errors'; diff --git a/packages/core/src/render3/errors.ts b/packages/core/src/render3/errors.ts index c390767208..f0dff261cf 100644 --- a/packages/core/src/render3/errors.ts +++ b/packages/core/src/render3/errors.ts @@ -6,8 +6,12 @@ * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ +import {InjectorType} from '../di/interface/defs'; +import {stringify} from '../util/stringify'; + import {TNode} from './interfaces/node'; + /** Called when directives inject each other (creating a circular dependency) */ export function throwCyclicDependencyError(token: any): never { throw new Error(`Cannot instantiate cyclic dependency! ${token}`); @@ -31,3 +35,20 @@ export function throwErrorIfNoChangesMode( // TODO: include debug context throw new Error(msg); } + +export function throwMixedMultiProviderError() { + throw new Error(`Cannot mix multi providers and regular providers`); +} + +export function throwInvalidProviderError( + ngModuleType?: InjectorType, providers?: any[], provider?: any) { + let ngModuleDetail = ''; + if (ngModuleType && providers) { + const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...'); + ngModuleDetail = + ` - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`; + } + + throw new Error( + `Invalid provider for the NgModule '${stringify(ngModuleType)}'` + ngModuleDetail); +} diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index d445ded545..889548a86b 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ -import {INJECTOR, Injector} from '../di/injector'; +import {Injector} from '../di/injector'; +import {INJECTOR} from '../di/injector_compatibility'; import {InjectFlags} from '../di/interface/injector'; import {StaticProvider} from '../di/interface/provider'; import {R3Injector, createInjector} from '../di/r3_injector'; diff --git a/packages/core/src/view/ng_module.ts b/packages/core/src/view/ng_module.ts index 37fed07345..6d064e91af 100644 --- a/packages/core/src/view/ng_module.ts +++ b/packages/core/src/view/ng_module.ts @@ -7,8 +7,8 @@ */ import {resolveForwardRef} from '../di/forward_ref'; -import {INJECTOR, Injector} from '../di/injector'; -import {setCurrentInjector} from '../di/injector_compatibility'; +import {Injector} from '../di/injector'; +import {INJECTOR, setCurrentInjector} from '../di/injector_compatibility'; import {getInjectableDef, ɵɵInjectableDef} from '../di/interface/defs'; import {APP_ROOT} from '../di/scope'; import {NgModuleRef} from '../linker/ng_module_factory'; diff --git a/packages/core/src/view/util.ts b/packages/core/src/view/util.ts index aaeec68753..5e88b2124b 100644 --- a/packages/core/src/view/util.ts +++ b/packages/core/src/view/util.ts @@ -7,7 +7,7 @@ */ import {WrappedValue, devModeEqual} from '../change_detection/change_detection'; -import {SOURCE} from '../di/injector'; +import {SOURCE} from '../di/injector_compatibility'; import {ViewEncapsulation} from '../metadata/view'; import {RendererType2} from '../render/api'; import {looseIdentical} from '../util/comparison'; diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index 62887f7ba6..057315aa95 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -5,21 +5,12 @@ { "name": "CIRCULAR" }, - { - "name": "CIRCULAR" - }, - { - "name": "EMPTY" - }, { "name": "EMPTY_ARRAY" }, { "name": "EmptyErrorImpl" }, - { - "name": "IDENT" - }, { "name": "INJECTOR" }, @@ -32,12 +23,6 @@ { "name": "InjectionToken" }, - { - "name": "Injector" - }, - { - "name": "MULTI_PROVIDER_FN" - }, { "name": "NEW_LINE" }, @@ -62,9 +47,6 @@ { "name": "NULL_INJECTOR" }, - { - "name": "NULL_INJECTOR" - }, { "name": "NullInjector" }, @@ -93,7 +75,7 @@ "name": "SkipSelf" }, { - "name": "StaticInjector" + "name": "THROW_IF_NOT_FOUND" }, { "name": "USE_VALUE" @@ -101,9 +83,6 @@ { "name": "UnsubscriptionErrorImpl" }, - { - "name": "_THROW_IF_NOT_FOUND" - }, { "name": "__forward_ref__" }, @@ -122,9 +101,6 @@ { "name": "catchInjectorError" }, - { - "name": "computeDeps" - }, { "name": "couldBeInjectableType" }, @@ -194,38 +170,29 @@ { "name": "makeRecord" }, - { - "name": "multiProviderMixError" - }, { "name": "providerToFactory" }, { "name": "providerToRecord" }, - { - "name": "recursivelyProcessProviders" - }, { "name": "resolveForwardRef" }, - { - "name": "resolveProvider" - }, - { - "name": "resolveToken" - }, { "name": "setCurrentInjector" }, - { - "name": "staticError" - }, { "name": "stringify" }, { - "name": "tryResolveToken" + "name": "throwCyclicDependencyError" + }, + { + "name": "throwInvalidProviderError" + }, + { + "name": "throwMixedMultiProviderError" }, { "name": "ɵɵdefineInjectable" diff --git a/packages/core/test/di/static_injector_spec.ts b/packages/core/test/di/static_injector_spec.ts index 778cc96ecf..6d4920006e 100644 --- a/packages/core/test/di/static_injector_spec.ts +++ b/packages/core/test/di/static_injector_spec.ts @@ -8,6 +8,7 @@ import {Inject, InjectionToken, Injector, Optional, Self, SkipSelf, forwardRef} from '@angular/core'; import {expect} from '@angular/platform-browser/testing/src/matchers'; +import {ivyEnabled, modifiedInIvy} from '@angular/private/testing'; import {stringify} from '../../src/util/stringify'; @@ -86,7 +87,7 @@ function factoryFn(a: any){} {provide: 'provider10', useValue: 1} ]; - describe(`StaticInjector`, () => { + modifiedInIvy('Ivy uses R3Injector').describe(`StaticInjector`, () => { it('should instantiate a class without dependencies', () => { const injector = Injector.create([Engine.PROVIDER]); @@ -413,9 +414,11 @@ function factoryFn(a: any){} [{provide: Car, useFactory: (e: Engine) => new Car(e), deps: [[Engine, new Self()]]}], parent); + const injectorName = ivyEnabled ? `R3Injector` : `StaticInjector`; + expect(() => child.get(Car)) .toThrowError( - `StaticInjectorError[${stringify(Car)} -> ${stringify(Engine)}]: \n` + + `${injectorName}Error[${stringify(Car)} -> ${stringify(Engine)}]: \n` + ' NullInjectorError: No provider for Engine!'); }); }); @@ -472,8 +475,11 @@ function factoryFn(a: any){} describe('displayName', () => { it('should work', () => { + const ivyError = `R3Injector[Engine, BrokenEngine, InjectionToken INJECTOR]`; + const viewEngineError = + `StaticInjector[Injector, InjectionToken INJECTOR, Engine, BrokenEngine]`; expect(Injector.create([Engine.PROVIDER, {provide: BrokenEngine, useValue: null}]).toString()) - .toEqual('StaticInjector[Injector, InjectionToken INJECTOR, Engine, BrokenEngine]'); + .toEqual(ivyEnabled ? ivyError : viewEngineError); }); }); } diff --git a/packages/core/test/view/ng_module_spec.ts b/packages/core/test/view/ng_module_spec.ts index 88b85f4441..ec81d5c0ed 100644 --- a/packages/core/test/view/ng_module_spec.ts +++ b/packages/core/test/view/ng_module_spec.ts @@ -8,7 +8,8 @@ import {NgModuleRef} from '@angular/core'; import {InjectFlags, inject} from '@angular/core/src/di'; -import {INJECTOR, Injector} from '@angular/core/src/di/injector'; +import {Injector} from '@angular/core/src/di/injector'; +import {INJECTOR} from '@angular/core/src/di/injector_compatibility'; import {ɵɵInjectableDef, ɵɵdefineInjectable} from '@angular/core/src/di/interface/defs'; import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/src/view'; import {moduleDef} from '@angular/core/src/view/ng_module'; diff --git a/packages/platform-browser/test/browser/bootstrap_spec.ts b/packages/platform-browser/test/browser/bootstrap_spec.ts index ce478f8782..3a057c3a74 100644 --- a/packages/platform-browser/test/browser/bootstrap_spec.ts +++ b/packages/platform-browser/test/browser/bootstrap_spec.ts @@ -232,10 +232,7 @@ function bootstrap( ]).then(null, (e: Error) => { let errorMsg: string; if (ivyEnabled) { - errorMsg = `R3InjectorError(TestModule)[IDontExist]: \n` + - ' StaticInjectorError(TestModule)[IDontExist]: \n' + - ' StaticInjectorError(Platform: core)[IDontExist]: \n' + - ' NullInjectorError: No provider for IDontExist!'; + errorMsg = `R3InjectorError(TestModule)[IDontExist -> IDontExist -> IDontExist]: \n`; } else { errorMsg = `StaticInjectorError(TestModule)[CustomCmp -> IDontExist]: \n` + ' StaticInjectorError(Platform: core)[CustomCmp -> IDontExist]: \n' +