Angular services as tree-shakable providers
When creating services to be used with Angular's Dependency Injection system, a provider is needed for each service.
Providers in AppModule
By adding services as providers
in the AppModule
, the build tools and compilers are unable to know
if that code is actually used in the application. They will always make these services available throughout the application even if they are never used. These services will not be able to take advantage of tree-shaking. More on tree-shaking down below.
@NgModule({
declarations: [
AppComponent,
],
imports: [],
providers: [
UserService,
PostService,
CategoryService,
],
bootstrap: [AppComponent]
})
export class AppModule { }
Rather than adding all of your services into the providers
array of AppModule
, as seen above, Angular recommends setting the providedIn
property of a service's @Injectable()
decorator. This will make such services tree-shakable. The service will still need to be injected where it is used.
Root application injector
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root',
})
export class UserService { }
By using root
, we specify that Angular should provide the UserService
in the root injector. It will be available throughout the application. We've just created a singleton service, which is a service for which only one instance exists in an application.
When using providedIn
on services, they will only be bundled in the application if they get used. These are called tree-shakable providers.
What is tree-shaking?
Tree shaking is a build process operation that helps with removing unused code from a code base. It's like shaking a a tree and having the dead leaves fall off the tree. Tree shaking only includes the code that is needed for the app to run.
Feature modules
We can also specify that a service should be provided in a particular @NgModule
. If we don't want UserService
to be available unless a UserModule
is imported, then we can specify that the service should be provided only in the module.
import { Injectable } from '@angular/core';
import { UserModule } from './user.module';
@Injectable({
providedIn: UserModule,
})
export class UserService { }
This is the recommended way to provide a service in a feature module. This method enables tree-shaking of the service if nothing ends up injecting it.