Closed
Description
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:
- Easy to implement
Cons:
di
will have to know aboutrender3
- Breaks tree shaking since any
@Injectable
will be pulling in at least some code ofrender3
.
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 aboutrender3
(needs to have a hook, see cons)
Cons:
di
has to have a hook into which externalrender3
can connect in order to redirectinject
intodirectiveInject
. 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
.