Keeping large dependencies off bundle in Angular

Sergey Gultyayev
3 min readNov 22, 2021

You are developing an app like usual, then, one day you realize that it takes quite some time to load. You inspect the initial bundle and it takes a few megabytes! How do you fix it? Let’s figure this out.

First off, let’s sort out which things can cause heavy initial bundles:

  • Large libraries
  • The app is a one big module

Analyze the bundle

As a doctor first checks his patient symptoms, we need to check what’s the root cause of our problem. We do so by building and analyzing our app. In the video, there is an explanation of how to do that. After sorting out what causes huge initial bundle size you can act.

Fixing large libraries usage

When using libraries such as Chart.js, Math.js and other heavy libraries you have several options:

  • The simplest one is to use this library in component’s imports and make sure the component is a part of a lazy loaded module. This way Webpack will sort things out for you.
  • A bit more challenging one is to create a service or a helper function that would use the webpack’s import feature, then use it in a component in an asynchronous way. This way, you will offload a library even if it’s used in the core bundle. Just show a loader for the time it’s being loaded.
  • Another alternative would be to use another library that provides the features you need while having a much smaller size.

If I were to lazy load the Chart.js I would write a service that would contain streams for each library I need to use. Also, note important things here:

  • Use of defer . from or just import resolve immediately when the service is created. defer allows us to delay the observable creation until we subscribe to it (because the promise is hidden in the callback).
  • shareReplay allows us to load a library once and immediately return it to any further calls.

When the service is created I only need to subscribe in a component

Code snippet with an example of using webpack’s lazy loading in a component

This way the library is only being loaded when the component is attached by using the webpack’s dynamic import feature.

Moment.js

Just stop using it. It’s already been deprecated, for the i18n you have the browser’s built-in Intl, as for the date transformations and parsing you could use alternative libraries such as date-fns etc which are tree shakeable.

Splitting app into modules

It’s possible that you don’t have any huge libraries, but the code itself is huge. The way to fix this is to use lazy loading for the routes, breaking down huge modules into smaller and more cohesive feature modules.

Also, one of the most often seen problems by me is the infamous SharedModule which may contain almost 70% of the application while 95% of its content is not being used across the whole app. You can read more about it in another article I wrote

--

--

Sergey Gultyayev

A front-end developer who uses Angular as a main framework and loves it