Webpack Bundle Analyzer To The Rescue Of The Angular’s Massive Bundle Size

small bundle size vs big bundle size

Getting Surprised By Angular Large Bundle Size

Have you ever been surprised by the size of your Angular bundle size? Imagine that you’re developing your application. The application is quite new, so basically it shouldn’t have a massy bundle size, right? Let’s also assume that this application is using an external vendor’s libraries.

So, after you imported another component from an external vendor, you have noticed that the Angular compiler is complaining about the budget size. To be precise, it’s giving you a warning. What to do?

What Is Budget And Why Do I Get That Warning?

Before we dig into one of the possible solutions to the problem, let’s understand what budgets are and why we did get that warning in the first place.

Budget is simply a value describing the size of an application that should trigger an event and which you can configure in angular.json. Such an event can be either warning or a compiler error. Budgets can be defined per environment. That means you can have a separate budget for production, staging, and dev environments. The budget can be defined for entire the application or part of it. For more, look at the angular doc.

Webpack Bundle Analyzer To The Rescue

Webpack analyzer is a tool that lets you visualize the size of the angular application output files with an interactive user interface. It gives you a very good picture of your application bundle size.

An example of warning in budgets
An example of warning in budgets

Using Webpack Bundle Analyzer For The Angular Application

First of all, we have to install the webpack bundle analyzer using npm. We can do it by using the following command

npm install --save-dev webpack-bundle-analyzer

Next, we have to generate a stats.json file. That file contains information about javascript scripts forming the Angular application. This is the output file that we will analyze with Webpack Bundle Analyzer. To do so, we have to run the following commands

1. ng build --stats-json 
2. webpack-bundle-analyzer dist/AngularWebpackAnalyser/stats.json

The first command generates the stats.json file. The second command is analyzing the Angular application dependencies and creates an interactive graph. We will use this graph to explore the application and see whether we have some bundle size issue (or, rather where we have it).

Sample Application

I’ve created a sample application that is available here https://github.com/lukaszreszke93/AngularWebpackAnalyser. The application is using Devexpress DataGrid. I really like Devexpress and the way their widgets work

In my application, that is using Devexpress widgets, I had one issue though, as you can probably guess, with bundle size. It’s easy to fix, but if you’re inattentive it’s highly probable that you’ll get there. The issue is about imports (and who doesn’t use auto imports, right?).

The application is available on GitHub as I already mentioned. I’m pasting the code samples for the app component, app module, and app service here as well. It will help us understand what caused a large bundle size.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { DxDataGridModule } from 'devextreme-angular';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, DxDataGridModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
import { Injectable } from '@angular/core';
import 'devextreme/data/odata/store';
import DataSource from 'devextreme/data/data_source';

@Injectable({
  providedIn: 'root',
})
export class AppService {
  getDataSource() { /* skipped for brevity */ }
}
import { Component } from '@angular/core';
import DataSource from 'devextreme/data/data_source';
import { AppService } from './app.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
 /* skipped for brevity */
  constructor(service: AppService) {
    this.dataSource = service.getDataSource();
  }
}

Notice that I’ve only used DataGrid widget and classes that handle the DataSource and OData Store.

Can you spot issue at this point? Let me know in comment.

Bundle Size Issue

Alright. So the application contains the issue (and the webpack analyzer output) similar that I had in my production application. The webpack analyzer graph looked more or less like this one

webpack analyzer output - interactive graph
Webpack analyzer interactive graph – can you spot the issue?

If you look at application size at this point, it’s very, very large (I did not use any production flag)

application size before bugfix - 22.4 MB
Application size befoe bugfix. 22.24MB

Quite large for a new application generated with Angular CLI and one external library used, right? Well… Let’s look at what we can get out of this webpack analyzer output.

Marked interesting parts with yellow and red colour
Highlighted areas that look suspicious

As I mentioned earlier, I have only used the Data Grid Widget. Why then do we have devextreme-angular-ui-tree-list.js, chart, lookup listed here (in the red box)?

Yellow part of the graph zoomed in. The dots convert into names of scripts that are attached.
Yellow part of the graph zoomed in. The dots convert into names of scripts that are attached.
Left part of the graph zoomed in. Did I import pivot grid somewhere?
Left part of the graph zoomed in. Did I import pivot grid somewhere?

Also here you can notice that there’s a lot of components that I did not import anywhere.

So What Is The Webpack Bundle Analyzer Telling Us?

Well, certainly it tells us two things. The first thing is that there’s something wrong with our application size. It is too large. The second thing is that there are JavaScript modules imported, that we are not explicitly referencing. The second issue is leading to the first one.

What Is Causing Large Angular Application Size?

Thanks to the Angular Warnings in console and Webpack Bundle Analyzer we have discovered that there’s something going on when it comes to the imports. In this case, the solution was quite easy to find. I’ve googled for bundle size issue in devexpress and stepped on GitHub issue. They have amazing support and fixing it turned out to be as easy as changing the way their modules are imported.

As a reminder, I did use automatic imports in Visual Studio Code.

So, previously, the import was

import { DxDataGridModule } from 'devextreme-angular';

The solution is to change it to

import { DxDataGridModule } from 'devextreme-angular/ui/data-grid';

This results in importing only the exact module that I need, instead of getting all the stuff that I have highlighted in previous sections. This makes a large difference when it comes to application size. This is the Webpack Bundle Analyzer output after import changes

Webpack Bundle Analyzer after fixing import
Webpack Bundle Analyzer after fixing import

You can notice that all the small boxes on the right side are gone. If you zoom in (get the project sources, generate stats.json and run webpack bundle analyzer) you’ll also notice that pivot grid import and other ones are also gone.

The last thing is the application bundle size. It dropped by almost 57%.

Before and after import statement change

Summary

  • Webpack Bundle Analyzer is a very useful tool that can be used to investigate problems with Angular application size (I think it’s worth mentioning at this stage that it also works with other frameworks)
  • One of the reasons for a massive bundle size can be import, that is not working as one would exactly expect
  • Setting budgets correctly in the Angular.json file can help to detect bundle size issues early in the development. Budgets can also be set up to be blockers