feat(compiler): mark @NgModules in provider lists for identification at runtime (#22005)
All of the providers in a module get compiled into a module definition in the factory file. Some of these providers are for the actual module types, as those are available for injection in Angular. For tree-shakeable tokens, the runtime needs to be able to distinguish which modules are present in an injector. This change adds a NodeFlag which tags those module providers for later identification. PR Close #22005
This commit is contained in:
parent
647b8595d0
commit
2d5e7d1b52
|
@ -194,6 +194,7 @@ export const enum NodeFlags {
|
||||||
TypeViewQuery = 1 << 27,
|
TypeViewQuery = 1 << 27,
|
||||||
StaticQuery = 1 << 28,
|
StaticQuery = 1 << 28,
|
||||||
DynamicQuery = 1 << 29,
|
DynamicQuery = 1 << 29,
|
||||||
|
TypeModuleProvider = 1 << 30,
|
||||||
CatQuery = TypeContentQuery | TypeViewQuery,
|
CatQuery = TypeContentQuery | TypeViewQuery,
|
||||||
|
|
||||||
// mutually exclusive values...
|
// mutually exclusive values...
|
||||||
|
|
|
@ -321,11 +321,11 @@ export class NgModuleProviderAnalyzer {
|
||||||
const ngModuleProvider = {token: {identifier: ngModuleType}, useClass: ngModuleType};
|
const ngModuleProvider = {token: {identifier: ngModuleType}, useClass: ngModuleType};
|
||||||
_resolveProviders(
|
_resolveProviders(
|
||||||
[ngModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors,
|
[ngModuleProvider], ProviderAstType.PublicService, true, sourceSpan, this._errors,
|
||||||
this._allProviders);
|
this._allProviders, true);
|
||||||
});
|
});
|
||||||
_resolveProviders(
|
_resolveProviders(
|
||||||
ngModule.transitiveModule.providers.map(entry => entry.provider).concat(extraProviders),
|
ngModule.transitiveModule.providers.map(entry => entry.provider).concat(extraProviders),
|
||||||
ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders);
|
ProviderAstType.PublicService, false, sourceSpan, this._errors, this._allProviders, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(): ProviderAst[] {
|
parse(): ProviderAst[] {
|
||||||
|
@ -448,7 +448,7 @@ function _transformProviderAst(
|
||||||
{eager, providers}: {eager: boolean, providers: CompileProviderMetadata[]}): ProviderAst {
|
{eager, providers}: {eager: boolean, providers: CompileProviderMetadata[]}): ProviderAst {
|
||||||
return new ProviderAst(
|
return new ProviderAst(
|
||||||
provider.token, provider.multiProvider, provider.eager || eager, providers,
|
provider.token, provider.multiProvider, provider.eager || eager, providers,
|
||||||
provider.providerType, provider.lifecycleHooks, provider.sourceSpan);
|
provider.providerType, provider.lifecycleHooks, provider.sourceSpan, provider.isModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _resolveProvidersFromDirectives(
|
function _resolveProvidersFromDirectives(
|
||||||
|
@ -461,7 +461,7 @@ function _resolveProvidersFromDirectives(
|
||||||
_resolveProviders(
|
_resolveProviders(
|
||||||
[dirProvider],
|
[dirProvider],
|
||||||
directive.isComponent ? ProviderAstType.Component : ProviderAstType.Directive, true,
|
directive.isComponent ? ProviderAstType.Component : ProviderAstType.Directive, true,
|
||||||
sourceSpan, targetErrors, providersByToken);
|
sourceSpan, targetErrors, providersByToken, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note: directives need to be able to overwrite providers of a component!
|
// Note: directives need to be able to overwrite providers of a component!
|
||||||
|
@ -470,10 +470,10 @@ function _resolveProvidersFromDirectives(
|
||||||
directivesWithComponentFirst.forEach((directive) => {
|
directivesWithComponentFirst.forEach((directive) => {
|
||||||
_resolveProviders(
|
_resolveProviders(
|
||||||
directive.providers, ProviderAstType.PublicService, false, sourceSpan, targetErrors,
|
directive.providers, ProviderAstType.PublicService, false, sourceSpan, targetErrors,
|
||||||
providersByToken);
|
providersByToken, false);
|
||||||
_resolveProviders(
|
_resolveProviders(
|
||||||
directive.viewProviders, ProviderAstType.PrivateService, false, sourceSpan, targetErrors,
|
directive.viewProviders, ProviderAstType.PrivateService, false, sourceSpan, targetErrors,
|
||||||
providersByToken);
|
providersByToken, false);
|
||||||
});
|
});
|
||||||
return providersByToken;
|
return providersByToken;
|
||||||
}
|
}
|
||||||
|
@ -481,7 +481,7 @@ function _resolveProvidersFromDirectives(
|
||||||
function _resolveProviders(
|
function _resolveProviders(
|
||||||
providers: CompileProviderMetadata[], providerType: ProviderAstType, eager: boolean,
|
providers: CompileProviderMetadata[], providerType: ProviderAstType, eager: boolean,
|
||||||
sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
|
sourceSpan: ParseSourceSpan, targetErrors: ParseError[],
|
||||||
targetProvidersByToken: Map<any, ProviderAst>) {
|
targetProvidersByToken: Map<any, ProviderAst>, isModule: boolean) {
|
||||||
providers.forEach((provider) => {
|
providers.forEach((provider) => {
|
||||||
let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
|
let resolvedProvider = targetProvidersByToken.get(tokenReference(provider.token));
|
||||||
if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
|
if (resolvedProvider != null && !!resolvedProvider.multiProvider !== !!provider.multi) {
|
||||||
|
@ -497,7 +497,7 @@ function _resolveProviders(
|
||||||
const isUseValue = !(provider.useClass || provider.useExisting || provider.useFactory);
|
const isUseValue = !(provider.useClass || provider.useExisting || provider.useFactory);
|
||||||
resolvedProvider = new ProviderAst(
|
resolvedProvider = new ProviderAst(
|
||||||
provider.token, !!provider.multi, eager || isUseValue, [provider], providerType,
|
provider.token, !!provider.multi, eager || isUseValue, [provider], providerType,
|
||||||
lifecycleHooks, sourceSpan);
|
lifecycleHooks, sourceSpan, isModule);
|
||||||
targetProvidersByToken.set(tokenReference(provider.token), resolvedProvider);
|
targetProvidersByToken.set(tokenReference(provider.token), resolvedProvider);
|
||||||
} else {
|
} else {
|
||||||
if (!provider.multi) {
|
if (!provider.multi) {
|
||||||
|
|
|
@ -192,7 +192,8 @@ export class ProviderAst implements TemplateAst {
|
||||||
constructor(
|
constructor(
|
||||||
public token: CompileTokenMetadata, public multiProvider: boolean, public eager: boolean,
|
public token: CompileTokenMetadata, public multiProvider: boolean, public eager: boolean,
|
||||||
public providers: CompileProviderMetadata[], public providerType: ProviderAstType,
|
public providers: CompileProviderMetadata[], public providerType: ProviderAstType,
|
||||||
public lifecycleHooks: LifecycleHooks[], public sourceSpan: ParseSourceSpan) {}
|
public lifecycleHooks: LifecycleHooks[], public sourceSpan: ParseSourceSpan,
|
||||||
|
readonly isModule: boolean) {}
|
||||||
|
|
||||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||||
// No visit method in the visitor for now...
|
// No visit method in the visitor for now...
|
||||||
|
|
|
@ -29,6 +29,9 @@ export function providerDef(ctx: OutputContext, providerAst: ProviderAst): {
|
||||||
if (providerAst.providerType === ProviderAstType.PrivateService) {
|
if (providerAst.providerType === ProviderAstType.PrivateService) {
|
||||||
flags |= NodeFlags.PrivateProvider;
|
flags |= NodeFlags.PrivateProvider;
|
||||||
}
|
}
|
||||||
|
if (providerAst.isModule) {
|
||||||
|
flags |= NodeFlags.TypeModuleProvider;
|
||||||
|
}
|
||||||
providerAst.lifecycleHooks.forEach((lifecycleHook) => {
|
providerAst.lifecycleHooks.forEach((lifecycleHook) => {
|
||||||
// for regular providers, we only support ngOnDestroy
|
// for regular providers, we only support ngOnDestroy
|
||||||
if (lifecycleHook === LifecycleHooks.OnDestroy ||
|
if (lifecycleHook === LifecycleHooks.OnDestroy ||
|
||||||
|
|
|
@ -36,8 +36,12 @@ export function moduleProvideDef(
|
||||||
|
|
||||||
export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition {
|
export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition {
|
||||||
const providersByKey: {[key: string]: NgModuleProviderDef} = {};
|
const providersByKey: {[key: string]: NgModuleProviderDef} = {};
|
||||||
|
const modules = [];
|
||||||
for (let i = 0; i < providers.length; i++) {
|
for (let i = 0; i < providers.length; i++) {
|
||||||
const provider = providers[i];
|
const provider = providers[i];
|
||||||
|
if (provider.flags & NodeFlags.TypeNgModule) {
|
||||||
|
modules.push(provider.token);
|
||||||
|
}
|
||||||
provider.index = i;
|
provider.index = i;
|
||||||
providersByKey[tokenKey(provider.token)] = provider;
|
providersByKey[tokenKey(provider.token)] = provider;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +49,8 @@ export function moduleDef(providers: NgModuleProviderDef[]): NgModuleDefinition
|
||||||
// Will be filled later...
|
// Will be filled later...
|
||||||
factory: null,
|
factory: null,
|
||||||
providersByKey,
|
providersByKey,
|
||||||
providers
|
providers,
|
||||||
|
modules,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -480,6 +480,7 @@ class NgModuleRef_ implements NgModuleData, InternalNgModuleRef<any> {
|
||||||
private _destroyed: boolean = false;
|
private _destroyed: boolean = false;
|
||||||
/** @internal */
|
/** @internal */
|
||||||
_providers: any[];
|
_providers: any[];
|
||||||
|
_modules: any[];
|
||||||
|
|
||||||
readonly injector: Injector = this;
|
readonly injector: Injector = this;
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ export interface Definition<DF extends DefinitionFactory<any>> { factory: DF|nul
|
||||||
export interface NgModuleDefinition extends Definition<NgModuleDefinitionFactory> {
|
export interface NgModuleDefinition extends Definition<NgModuleDefinitionFactory> {
|
||||||
providers: NgModuleProviderDef[];
|
providers: NgModuleProviderDef[];
|
||||||
providersByKey: {[tokenKey: string]: NgModuleProviderDef};
|
providersByKey: {[tokenKey: string]: NgModuleProviderDef};
|
||||||
|
modules: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NgModuleDefinitionFactory extends DefinitionFactory<NgModuleDefinition> {}
|
export interface NgModuleDefinitionFactory extends DefinitionFactory<NgModuleDefinition> {}
|
||||||
|
@ -192,6 +193,7 @@ export const enum NodeFlags {
|
||||||
TypeViewQuery = 1 << 27,
|
TypeViewQuery = 1 << 27,
|
||||||
StaticQuery = 1 << 28,
|
StaticQuery = 1 << 28,
|
||||||
DynamicQuery = 1 << 29,
|
DynamicQuery = 1 << 29,
|
||||||
|
TypeNgModule = 1 << 30,
|
||||||
CatQuery = TypeContentQuery | TypeViewQuery,
|
CatQuery = TypeContentQuery | TypeViewQuery,
|
||||||
|
|
||||||
// mutually exclusive values...
|
// mutually exclusive values...
|
||||||
|
@ -293,6 +295,11 @@ export const enum DepFlags {
|
||||||
Value = 2 << 2,
|
Value = 2 << 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface InjectableDef {
|
||||||
|
scope: any;
|
||||||
|
factory: () => any;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TextDef { prefix: string; }
|
export interface TextDef { prefix: string; }
|
||||||
|
|
||||||
export interface QueryDef {
|
export interface QueryDef {
|
||||||
|
|
Loading…
Reference in New Issue