Use providedIn for the Angular Service registration to reduce bundle size

Share this video with your friends

Social Share Links

Send Tweet
Published 4 years ago
Updated 9 months ago

As we've seen in my course on Angular Service Injection with the DI there are different ways to register a service with Angular's Dependency Injector. The major approaches (as of Angular v8+) is to either register the service on the NgModule providers array, or to directly use the @Injectable({ providedIn: 'root' }) decorator.

In this lesson we're going to specifically look into the impact of those two methods to the final bundle size

More details can also be read in one of my recent blog posts

Instructor: [0:00] Let's first have a look at the setup here. We have a simplification. It has a data access module with its data service, and that service is imported on Feature1 and Feature2. Both of them are lazy loaded. If I click here, you can see jouse has been pulled in, and similarly here.

[0:18] I want to have a look, in this video specifically, on the bundle size and what implications there are based on how we register our data service. Let's remove this here as it's not relevant for this video. First of all, let's have a look at the current setup in terms of the data service registration.

[0:35] I'm using on purpose @Injectable here, and I registered a service here on the providers array of my module. That module, in turn, is being imported again on Feature1Module and as well on Feature2Module. That is necessary for making the data service available to these two feature modules such that then an actual components to data service can be used. Let's compile this. I'm just using build here without the production build so we can read the source that gets produced.

[1:10] Now if we go to our dist folder, what you see here is we have the main bundles and vendor bundles, we have the different modules here in Feature1Module and Feature2Module, and now since we have common chunk enabled, you can check out my blog for how to disable that if needed, the common parts between Feature1 and Feature2Module, which is our data access module and data service, will be compiled into that common chunk.

[1:36] Let's have a look what we have in here. We have the actual data service, and we also have the data access module itself. Obviously, both of them are in here, because we use all of them in our app logic. What happens if we start modifying the source?

[1:51] Assume that we have the data service registered on the dat access module, but actually, we don't need that service. Assume that we need to module in those Feature1 and Feature2Modules, so let's remove this here. Let's leave the registration here, because maybe the data access module in a real-world scenario might have more things registered on here, which we are actually using, like other services, for instance.

[2:14] Let's remove them also from the component two here, from FeatureModule2. That way, we get rid of the data service users. In general, we don't use data service now anymore.

[2:27] Let's again recompile. If we go up here again in the common chunk, what you will see is we'll still see the data service in here, although tactically, that service is not being used by our app. The only place where we have it is the registration on that data access module.

[2:47] The similar thing is, the same thing is when we do it in production. If we do a production build and we again go up here, we still have our common script, and if we search for data service, we still see the data service in here. Angular is not going to remove that.

[3:06] This, however, is quite different if we use the providedIn syntax. If you go in here and we use that syntax, we use the providedIn: 'root,' and as a result, we can remove the registration on our module here.

[3:21] Now, the situation is exactly the same. We still use the data access module here in the Feature1Module. We still import that. We also have the x module here, but since we used the providedIn: 'root,' our data service is not being registered anymore and it's not imported anywhere in our application.

[3:40] Again, if we build our application now, let's check out again the CommonJS, and now, what you see is we have the data access module in here. There's no trace of our data service because it's never imported anywhere, and so it can be avoided.

[3:57] As you can see, the fact of using that providedIn syntax not only has other benefits in terms of having a singleton instance even for lazy-loaded modules, but it also has a direct impact on the actual final bundle size.