Lazy-loading for better Angular performance

Before we continue our series on standalone components, it is important to talk about the most important tool at our disposal to create more performant Angular applications: Lazy-loading.

When we use lazy-loading, instead of building our application as one single bundle of code that gets downloaded as soon as our user accesses the app in a browser, we divide our code into several different pieces that get downloaded on-demand when they are needed.

For instance, without lazy-loading, if our application is 25 MB big in terms of Javascript code, a browser has to download, then parse, and run those 25 MB of code, which can slow things down a lot on mobile devices or slower internet connections.

Instead, we can divide our application into different modules containing components, pipes, directives, and services. In our example, let’s assume we create an AdminModule that includes all of the features needed for the Admin section of the application. If this module ends up containing 10 MB of code and we use lazy-loading with it, then the initial bundle of the application is down from 25 MB to 15 MB, which is a big difference.

Only Admin users would ever have to download the 10 MB of code for the admin section, which is great for both performance and safety (hackers can’t reverse-engineer code that has never been downloaded in their browser).

The best part of lazy-loading is that a single line of code initiates it in our router config:

The above line will get the Angular compiler to automatically create a bundle of code for AdminModule and enable lazy-loading of that code when /items is accessed. That’s it!

Union types in TypeScript

Yesterday, we talked about any, unknown, and the pros and cons of using such types.

Today, let’s focus on union types, an alternative to enums that are more performant and flexible to describe custom types. Let’s assume we need to support different currencies in our application. Since currencies are mostly a code/symbol, we could take the easy route and do the following:

But this doesn’t help us much. For example, is any string a valid currency? Definitely not. So a better option would be to create an enum for it and describe all possible values in it:

Now we have a proper type to describe what a Currency is. But enums aren’t that convenient because they can’t be used as-is in an Angular component template, requiring some workarounds. Also, they get compiled into a monster structure of JavaScript that increases the size of your code bundle for no valid reason since we don’t have type-checking at runtime in the browser.

Enter union types

Union types solve all these problems. They’re lightweight and do not get compiled into anything at all, which means they’re always more performant than enums (less code to download + less code to interpret = faster app in the browser). They guarantee type safety and can be made out of anything, including strings:

A lot more can be done with union types, such as having more options than just one single type for a given variable:

Angular uses union types a lot. For instance, if you’ve ever used the canActivate router guard, its signature supports up to 6 different return types, all defined with union types:

And we can have unions of union types when more granularity is needed with specific sub-types: