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:
crisbeto
2019-09-01 12:26:04 +02:00
committed by atscott
parent 2729747225
commit 4e35e348af
33 changed files with 695 additions and 295 deletions

View File

@ -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')]))])
};
}