Search code examples
angularjavascript-frameworkweb-frameworks

When does the Angular 2+ service get provided


I have read quite a bit about Angular dependency injection system, but still can't seem to find the answer to one very specific question.

The providers registered via the @Module's providers: [] array are 'picked up' by the module's current (closest parent) Injector. They will generally be registered in the root Injector, unless the module is lazy loaded which creates a separate injection context which works kind of like a {} block (the outer providers are accessible inside but not vise versa, and the inner providers take precedence). If the providers are registered in the @Component's providers: [] array, they also are injected in the separate context which only includes the component itself and its children.

What happens to the services registered inside the @Service() decorator is however a mystery to me. What if the service is never used anywhere? Or what if the @Service({providedIn: root}) is used only in a lazy-loaded module? And what if it's providedIn: SomeLazyLoadedModule? And should such services ever be mentioned in the module's providers array?

The only concrete information I was able to find on the topic was 'The AOT compiler may perform some optimizitions such as tree shaking', which didn't really clarify a lot, to be honest.

Please feel free to correct me if some of the statements above are wrong.


Solution

  • First of all, there is no @Service decorator. It's named @Injectable.

    If you decorate a service with just @Injectable(), then it's not provided anywhere, unless you add it to the providers array of a module or component.

    If you decorate it with @Injectable({ providedIn: 'root' }), then it's provided in the root module, i.e. it's equivalent to adding it to the providers array of the root module except that this allows to completely ignore the service and to not add it to any bundle if it's never injected anywhere: in that case, since it's not in any other TypeScript file's imports, it can be tree-shaken: nothing uses that service, so bundling it is useless.

    If you decorate it with @Injectable({ providedIn: SomeModule }), then it's provided in the module SomeModule, i.e. it's equivalent to adding it to the providers array of the module SomeModule With the same exception as above, i.e. if nothing imports it, it can be tree-shaken.