In this post I will show one of the pitfalls of bundling in Angular.

I will show an example of how NgModule imports may impact bundle sizes.

Tree shaking can be a great bundle optimization technique if you structure your code correctly. There are however a few pitfalls you should be aware of.

There are limits to what a Tree shaker like Rollup can remove from an Angular application.

In my sample I will show that Rollup may not be able to remove components and services that you don’t technically need in your application.

One area to pay attention to is code referenced from NgModule configuration arrays (e.g. providers, declarations, entryComponents, exports).

Listing components and services in the various arrays in an NgModule is effectively forcing inclusions of the listed services and components in your bundle.

Your application may not actually need these services or components. It may never create a single instance of any of them.

However, Rollup has to include the code from these imports regardless.

The take away is that registering the imported symbol in the NgModule counts as using the code. As a result it‘s included in the bundle.

In the following example I have defined a simple app module where I import a module called “SharedModule”.

Behind the scenes the shared module declares a component and provides a service.

In my particular case I might want to use the service, but not the component.

Ideally I would like for the unused component to be shaken out of my bundle.

However since both are registered with the shared module, I am forced to include both in my bundle.

app.module.js
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { SharedModule } from '../modules/shared/shared-module'; @NgModule({ imports: [ SharedModule, BrowserModule, HttpModule], declarations: [AppComponent], bootstrap: [AppComponent] }) export class AppModule {}
person-module.js
import { PersonComponent } from './person.component'; import { PersonService } from './person.service'; @NgModule({ declarations: [PersonComponent], providers: [PersonService], exports: [PersonComponent, PersonService] }) export class SharedModule { }

This behavior is not a problem with Rollup, but rather something to be mindful of when architecting shared modules.

It might be convenient to “barrel” a bunch of commonly used components together in the same shared module.

This type of grouping may reduce the number of repetitive import statements in your application. It does potentially come at the cost of bigger bundles though.