feat: tree-shakeable providers API updates (#22655)

Rename @Injectable({scope -> providedIn}).

Instead of {providedIn: APP_ROOT_SCOPE}, accept {providedIn: 'root'}.
Also, {providedIn: null} implies the injectable should not be added
to any scope.

PR Close #22655
This commit is contained in:
Alex Rickabaugh
2018-03-07 15:10:38 -08:00
committed by Kara Erickson
parent 21e44c6ba9
commit db56836425
29 changed files with 219 additions and 114 deletions

View File

@ -7,12 +7,13 @@
*/
import {resolveForwardRef} from '../di/forward_ref';
import {InjectableDef} from '../di/injectable';
import {InjectFlags, Injector, setCurrentInjector} from '../di/injector';
import {APP_ROOT_SCOPE} from '../di/scope';
import {APP_ROOT} from '../di/scope';
import {NgModuleRef} from '../linker/ng_module_factory';
import {stringify} from '../util';
import {DepDef, DepFlags, InjectableDef, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
import {DepDef, DepFlags, NgModuleData, NgModuleDefinition, NgModuleProviderDef, NodeFlags} from './types';
import {splitDepsDsl, tokenKey} from './util';
const UNDEFINED_VALUE = new Object();
@ -20,12 +21,6 @@ const UNDEFINED_VALUE = new Object();
const InjectorRefTokenKey = tokenKey(Injector);
const NgModuleRefTokenKey = tokenKey(NgModuleRef);
export function injectableDef(scope: any, factory: () => any): InjectableDef {
return {
scope, factory,
};
}
export function moduleProvideDef(
flags: NodeFlags, token: any, value: any,
deps: ([DepFlags, any] | any)[]): NgModuleProviderDef {
@ -47,7 +42,7 @@ export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition
let isRoot: boolean = false;
for (let i = 0; i < providers.length; i++) {
const provider = providers[i];
if (provider.token === APP_ROOT_SCOPE) {
if (provider.token === APP_ROOT) {
isRoot = true;
}
if (provider.flags & NodeFlags.TypeNgModule) {
@ -103,7 +98,7 @@ export function resolveNgModuleDep(
}
return providerInstance === UNDEFINED_VALUE ? undefined : providerInstance;
} else if (depDef.token.ngInjectableDef && targetsModule(data, depDef.token.ngInjectableDef)) {
const injectableDef = depDef.token.ngInjectableDef as InjectableDef;
const injectableDef = depDef.token.ngInjectableDef as InjectableDef<any>;
const key = tokenKey;
const index = data._providers.length;
data._def.providersByKey[depDef.tokenKey] = {
@ -129,9 +124,9 @@ function moduleTransitivelyPresent(ngModule: NgModuleData, scope: any): boolean
return ngModule._def.modules.indexOf(scope) > -1;
}
function targetsModule(ngModule: NgModuleData, def: InjectableDef): boolean {
return def.scope != null && (moduleTransitivelyPresent(ngModule, def.scope) ||
def.scope === APP_ROOT_SCOPE && ngModule._def.isRoot);
function targetsModule(ngModule: NgModuleData, def: InjectableDef<any>): boolean {
return def.providedIn != null && (moduleTransitivelyPresent(ngModule, def.providedIn) ||
def.providedIn === 'root' && ngModule._def.isRoot);
}
function _createProviderInstance(ngModule: NgModuleData, providerDef: NgModuleProviderDef): any {

View File

@ -8,13 +8,14 @@
import {isDevMode} from '../application_ref';
import {DebugElement, DebugNode, EventListener, getDebugNode, indexDebugNode, removeDebugNodeFromIndex} from '../debug/debug_node';
import {Injector} from '../di';
import {InjectableType, Injector} from '../di';
import {ErrorHandler} from '../error_handler';
import {ComponentFactory} from '../linker/component_factory';
import {NgModuleRef} from '../linker/ng_module_factory';
import {Renderer2, RendererFactory2, RendererStyleFlags2, RendererType2} from '../render/api';
import {Sanitizer} from '../sanitization/security';
import {Type} from '../type';
import {tokenKey} from '../view/util';
import {isViewDebugError, viewDestroyedError, viewWrappedDebugError} from './errors';
import {resolveDep} from './provider';
@ -162,10 +163,15 @@ function debugCreateNgModuleRef(
}
const providerOverrides = new Map<any, ProviderOverride>();
const providerOverridesWithScope = new Map<InjectableType<any>, ProviderOverride>();
const viewDefOverrides = new Map<any, ViewDefinition>();
function debugOverrideProvider(override: ProviderOverride) {
providerOverrides.set(override.token, override);
if (typeof override.token === 'function' && override.token.ngInjectableDef &&
typeof override.token.ngInjectableDef.providedIn === 'function') {
providerOverridesWithScope.set(override.token as InjectableType<any>, override);
}
}
function debugOverrideComponentView(comp: any, compFactory: ComponentFactory<any>) {
@ -176,6 +182,7 @@ function debugOverrideComponentView(comp: any, compFactory: ComponentFactory<any
function debugClearOverrides() {
providerOverrides.clear();
providerOverridesWithScope.clear();
viewDefOverrides.clear();
}
@ -266,6 +273,14 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi
hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior;
}
});
def.modules.forEach(module => {
providerOverridesWithScope.forEach((override, token) => {
if (token.ngInjectableDef.providedIn === module) {
hasOverrides = true;
hasDeprecatedOverrides = hasDeprecatedOverrides || override.deprecatedBehavior;
}
});
});
return {hasOverrides, hasDeprecatedOverrides};
}
@ -285,6 +300,23 @@ function applyProviderOverridesToNgModule(def: NgModuleDefinition): NgModuleDefi
provider.value = override.value;
}
}
if (providerOverridesWithScope.size > 0) {
let moduleSet = new Set<any>(def.modules);
providerOverridesWithScope.forEach((override, token) => {
if (moduleSet.has(token.ngInjectableDef.providedIn)) {
let provider = {
token: token,
flags:
override.flags | (hasDeprecatedOverrides ? NodeFlags.LazyProvider : NodeFlags.None),
deps: splitDepsDsl(override.deps),
value: override.value,
index: def.providers.length,
};
def.providers.push(provider);
def.providersByKey[tokenKey(token)] = provider;
}
});
}
}
}

View File

@ -297,11 +297,6 @@ export const enum DepFlags {
Value = 1 << 3,
}
export interface InjectableDef {
scope: any;
factory: () => any;
}
export interface TextDef { prefix: string; }
export interface QueryDef {