refactor(ivy): generate ngFactoryDef for injectables (#32433)
With #31953 we moved the factories for components, directives and pipes into a new field called `ngFactoryDef`, however I decided not to do it for injectables, because they needed some extra logic. These changes set up the `ngFactoryDef` for injectables as well. For reference, the extra logic mentioned above is that for injectables we have two code paths: 1. For injectables that don't configure how they should be instantiated, we create a `factory` that proxies to `ngFactoryDef`: ``` // Source @Injectable() class Service {} // Output class Service { static ngInjectableDef = defineInjectable({ factory: () => Service.ngFactoryFn(), }); static ngFactoryFn: (t) => new (t || Service)(); } ``` 2. For injectables that do configure how they're created, we keep the `ngFactoryDef` and generate the factory based on the metadata: ``` // Source @Injectable({ useValue: DEFAULT_IMPL, }) class Service {} // Output export class Service { static ngInjectableDef = defineInjectable({ factory: () => DEFAULT_IMPL, }); static ngFactoryFn: (t) => new (t || Service)(); } ``` PR Close #32433
This commit is contained in:
@ -40,9 +40,7 @@ export interface CompilerFacade {
|
||||
compileBase(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3BaseMetadataFacade):
|
||||
any;
|
||||
compileFactory(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string,
|
||||
meta: R3PipeMetadataFacade|R3DirectiveMetadataFacade|R3ComponentMetadataFacade,
|
||||
isPipe?: boolean): any;
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade): any;
|
||||
|
||||
createParseSourceSpan(kind: string, typeName: string, sourceUrl: string): ParseSourceSpan;
|
||||
|
||||
@ -94,7 +92,6 @@ export interface R3InjectableMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
typeArgumentCount: number;
|
||||
ctorDeps: R3DependencyMetadataFacade[]|null;
|
||||
providedIn: any;
|
||||
useClass?: any;
|
||||
useFactory?: any;
|
||||
@ -164,6 +161,15 @@ export interface R3BaseMetadataFacade {
|
||||
viewQueries?: R3QueryMetadataFacade[];
|
||||
}
|
||||
|
||||
export interface R3FactoryDefMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
typeArgumentCount: number;
|
||||
deps: R3DependencyMetadataFacade[]|null;
|
||||
injectFn: 'directiveInject'|'inject';
|
||||
isPipe: boolean;
|
||||
}
|
||||
|
||||
export type ViewEncapsulation = number;
|
||||
|
||||
export type ChangeDetectionStrategy = number;
|
||||
|
@ -63,6 +63,7 @@ export class Identifiers {
|
||||
|
||||
};
|
||||
static inject: o.ExternalReference = {name: 'ɵɵinject', moduleName: CORE};
|
||||
static directiveInject: o.ExternalReference = {name: 'ɵɵdirectiveInject', moduleName: CORE};
|
||||
static INJECTOR: o.ExternalReference = {name: 'INJECTOR', moduleName: CORE};
|
||||
static Injector: o.ExternalReference = {name: 'Injector', moduleName: CORE};
|
||||
static ɵɵdefineInjectable: o.ExternalReference = {name: 'ɵɵdefineInjectable', moduleName: CORE};
|
||||
|
@ -6,10 +6,9 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {InjectFlags} from './core';
|
||||
import {Identifiers} from './identifiers';
|
||||
import * as o from './output/output_ast';
|
||||
import {R3DependencyMetadata, R3FactoryDelegateType, R3FactoryMetadata, compileFactoryFunction} from './render3/r3_factory';
|
||||
import {R3DependencyMetadata, R3FactoryDelegateType, compileFactoryFunction} from './render3/r3_factory';
|
||||
import {mapToMapExpression, typeWithParameters} from './render3/util';
|
||||
|
||||
export interface InjectableDef {
|
||||
@ -22,7 +21,6 @@ export interface R3InjectableMetadata {
|
||||
name: string;
|
||||
type: o.Expression;
|
||||
typeArgumentCount: number;
|
||||
ctorDeps: R3DependencyMetadata[]|'invalid'|null;
|
||||
providedIn: o.Expression;
|
||||
useClass?: o.Expression;
|
||||
useFactory?: o.Expression;
|
||||
@ -38,7 +36,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef {
|
||||
name: meta.name,
|
||||
type: meta.type,
|
||||
typeArgumentCount: meta.typeArgumentCount,
|
||||
deps: meta.ctorDeps,
|
||||
deps: [],
|
||||
injectFn: Identifiers.inject,
|
||||
};
|
||||
|
||||
@ -67,19 +65,22 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef {
|
||||
} else if (useClassOnSelf) {
|
||||
result = compileFactoryFunction(factoryMeta);
|
||||
} else {
|
||||
result = compileFactoryFunction({
|
||||
...factoryMeta,
|
||||
delegate: meta.useClass,
|
||||
delegateType: R3FactoryDelegateType.Factory,
|
||||
});
|
||||
result = delegateToFactory(meta.useClass);
|
||||
}
|
||||
} else if (meta.useFactory !== undefined) {
|
||||
result = compileFactoryFunction({
|
||||
...factoryMeta,
|
||||
delegate: meta.useFactory,
|
||||
delegateDeps: meta.userDeps || [],
|
||||
delegateType: R3FactoryDelegateType.Function,
|
||||
});
|
||||
if (meta.userDeps !== undefined) {
|
||||
result = compileFactoryFunction({
|
||||
...factoryMeta,
|
||||
delegate: meta.useFactory,
|
||||
delegateDeps: meta.userDeps || [],
|
||||
delegateType: R3FactoryDelegateType.Function,
|
||||
});
|
||||
} else {
|
||||
result = {
|
||||
statements: [],
|
||||
factory: o.fn([], [new o.ReturnStatement(meta.useFactory.callFn([]))])
|
||||
};
|
||||
}
|
||||
} else if (meta.useValue !== undefined) {
|
||||
// Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for
|
||||
// client code because meta.useValue is an Expression which will be defined even if the actual
|
||||
@ -95,7 +96,7 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef {
|
||||
expression: o.importExpr(Identifiers.inject).callFn([meta.useExisting]),
|
||||
});
|
||||
} else {
|
||||
result = compileFactoryFunction(factoryMeta);
|
||||
result = delegateToFactory(meta.type);
|
||||
}
|
||||
|
||||
const token = meta.type;
|
||||
@ -112,3 +113,12 @@ export function compileInjectable(meta: R3InjectableMetadata): InjectableDef {
|
||||
statements: result.statements,
|
||||
};
|
||||
}
|
||||
|
||||
function delegateToFactory(type: o.Expression) {
|
||||
return {
|
||||
statements: [],
|
||||
// () => meta.type.ngFactoryDef(t)
|
||||
factory: o.fn([new o.FnParam('t', o.DYNAMIC_TYPE)], [new o.ReturnStatement(type.callMethod(
|
||||
'ngFactoryDef', [o.variable('t')]))])
|
||||
};
|
||||
}
|
||||
|
@ -7,9 +7,10 @@
|
||||
*/
|
||||
|
||||
|
||||
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3BaseMetadataFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
|
||||
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, R3BaseMetadataFacade, R3ComponentMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3FactoryDefMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
|
||||
import {ConstantPool} from './constant_pool';
|
||||
import {HostBinding, HostListener, Input, Output, Type} from './core';
|
||||
import {Identifiers} from './identifiers';
|
||||
import {compileInjectable} from './injectable_compiler_2';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from './ml_parser/interpolation_config';
|
||||
import {DeclareVarStmt, Expression, LiteralExpr, Statement, StmtModifier, WrappedNodeExpr} from './output/output_ast';
|
||||
@ -59,7 +60,6 @@ export class CompilerFacadeImpl implements CompilerFacade {
|
||||
useFactory: wrapExpression(facade, USE_FACTORY),
|
||||
useValue: wrapExpression(facade, USE_VALUE),
|
||||
useExisting: wrapExpression(facade, USE_EXISTING),
|
||||
ctorDeps: convertR3DependencyMetadataArray(facade.ctorDeps),
|
||||
userDeps: convertR3DependencyMetadataArray(facade.userDeps) || undefined,
|
||||
});
|
||||
|
||||
@ -154,14 +154,15 @@ export class CompilerFacadeImpl implements CompilerFacade {
|
||||
}
|
||||
|
||||
compileFactory(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string,
|
||||
meta: R3PipeMetadataFacade|R3DirectiveMetadataFacade|R3ComponentMetadataFacade,
|
||||
isPipe = false) {
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3FactoryDefMetadataFacade) {
|
||||
const factoryRes = compileFactoryFromMetadata({
|
||||
name: meta.name,
|
||||
type: new WrappedNodeExpr(meta.type),
|
||||
typeArgumentCount: meta.typeArgumentCount,
|
||||
deps: convertR3DependencyMetadataArray(meta.deps), isPipe
|
||||
deps: convertR3DependencyMetadataArray(meta.deps),
|
||||
injectFn: meta.injectFn === 'directiveInject' ? Identifiers.directiveInject :
|
||||
Identifiers.inject,
|
||||
isPipe: meta.isPipe
|
||||
});
|
||||
return this.jitExpression(
|
||||
factoryRes.factory, angularCoreEnv, sourceMapUrl, factoryRes.statements);
|
||||
|
@ -86,7 +86,8 @@ export interface R3FactoryDefMetadata {
|
||||
name: string;
|
||||
type: o.Expression;
|
||||
typeArgumentCount: number;
|
||||
deps: R3DependencyMetadata[]|null;
|
||||
deps: R3DependencyMetadata[]|'invalid'|null;
|
||||
injectFn: o.ExternalReference;
|
||||
isPipe?: boolean;
|
||||
}
|
||||
|
||||
@ -267,8 +268,7 @@ export function compileFactoryFromMetadata(meta: R3FactoryDefMetadata): R3Factor
|
||||
type: meta.type,
|
||||
deps: meta.deps,
|
||||
typeArgumentCount: meta.typeArgumentCount,
|
||||
// TODO(crisbeto): this should be refactored once we start using it for injectables.
|
||||
injectFn: R3.directiveInject,
|
||||
injectFn: meta.injectFn,
|
||||
},
|
||||
meta.isPipe);
|
||||
}
|
||||
|
@ -89,7 +89,8 @@ export function compilePipeFromRender2(
|
||||
pure: pipe.pure,
|
||||
};
|
||||
const res = compilePipeFromMetadata(metadata);
|
||||
const factoryRes = compileFactoryFromMetadata({...metadata, isPipe: true});
|
||||
const factoryRes =
|
||||
compileFactoryFromMetadata({...metadata, injectFn: R3.directiveInject, isPipe: true});
|
||||
const definitionField = outputCtx.constantPool.propertyNameOf(DefinitionKind.Pipe);
|
||||
const ngFactoryDefStatement = new o.ClassStmt(
|
||||
/* name */ name,
|
||||
|
@ -325,7 +325,7 @@ export function compileDirectiveFromRender2(
|
||||
|
||||
const meta = directiveMetadataFromGlobalMetadata(directive, outputCtx, reflector);
|
||||
const res = compileDirectiveFromMetadata(meta, outputCtx.constantPool, bindingParser);
|
||||
const factoryRes = compileFactoryFromMetadata(meta);
|
||||
const factoryRes = compileFactoryFromMetadata({...meta, injectFn: R3.directiveInject});
|
||||
const ngFactoryDefStatement = new o.ClassStmt(
|
||||
name, null,
|
||||
[new o.ClassField(
|
||||
@ -378,7 +378,7 @@ export function compileComponentFromRender2(
|
||||
i18nUseExternalIds: true,
|
||||
};
|
||||
const res = compileComponentFromMetadata(meta, outputCtx.constantPool, bindingParser);
|
||||
const factoryRes = compileFactoryFromMetadata(meta);
|
||||
const factoryRes = compileFactoryFromMetadata({...meta, injectFn: R3.directiveInject});
|
||||
const ngFactoryDefStatement = new o.ClassStmt(
|
||||
name, null,
|
||||
[new o.ClassField(
|
||||
|
Reference in New Issue
Block a user