Currently we generate inject for @Injectable and directiveInject for @Component and @Directive. This works fine since @Injectable declared as part of @NgModule does not need to see anything from the Element Injector Tree.
However this does not work in the case when @Injectable is used with @Component.providers (or @Component.viewProviders) because in that case the @Injectable can see into the Element Injector Tree.
Possible fixes are:
Mark services in @Component.providers using inject (:thumbsdown:)
non-starter as it breaks locality.
Have only one inject (:thumbsdown:)
This would require merging directiveInject into inject
Pros:
Cons:
di will have to know about render3
- Breaks tree shaking since any
@Injectable will be pulling in at least some code of render3.
Have ComponentDefFeature which would patch inject to act like directiveInject only when @Component.providers are used (:thumbsup:)
Pros:
- Tree shaking works as expected.
di does not need to know about render3 (needs to have a hook, see cons)
Cons:
di has to have a hook into which external render3 can connect in order to redirect inject into directiveInject. Since this is a private hook, it should be small cost.
Syntax
@Inejctable()
class SomeService {
constructor(dep: SomeDep) {}
static ngInjectableDef = defineInjectable({
factory: () => new SomeService(inject(SomeDep));
});
}
@Component({
...,
provides: [SomeService]
})
class MyComponent {
static ngComponentDef = defineCompoent({
...,
provides: [SomeService],
features: [ComponetProvidersFeature]
});
}
ComponetProvidersFeature would than use some private API to patch the inject to go through the directiveInject in cases where the factory is called as a consequence of @Component.providers.
Currently we generate
injectfor@InjectableanddirectiveInjectfor@Componentand@Directive. This works fine since@Injectabledeclared as part of@NgModuledoes not need to see anything from the Element Injector Tree.However this does not work in the case when
@Injectableis used with@Component.providers(or@Component.viewProviders) because in that case the@Injectablecan see into the Element Injector Tree.Possible fixes are:
Mark services in
@Component.providersusinginject(:thumbsdown:)non-starter as it breaks locality.
Have only one
inject(:thumbsdown:)This would require merging
directiveInjectintoinjectPros:
Cons:
diwill have to know aboutrender3@Injectablewill be pulling in at least some code ofrender3.Have
ComponentDefFeaturewhich would patchinjectto act likedirectiveInjectonly when@Component.providersare used (:thumbsup:)Pros:
didoes not need to know aboutrender3(needs to have a hook, see cons)Cons:
dihas to have a hook into which externalrender3can connect in order to redirectinjectintodirectiveInject. Since this is a private hook, it should be small cost.Syntax
ComponetProvidersFeaturewould than use some private API to patch theinjectto go through thedirectiveInjectin cases where the factory is called as a consequence of@Component.providers.