Angular Tools for High Performance

Angular Tools for High Performance

Angular Tools for High Performance

This post,contains a list of new tools and practices that can help us build faster Angular apps and monitor their performance over time. In each section, you’ll find links for further reference on how to incorporate them in your project. The focus of this post is on decreasing initial load time and speeding up page navigation using code-splitting and preloading

We’ll look at the following topics:

  • Code-splitting
  • Preloading strategies
  • Performance budgets
  • Efficient serving

JavaScript and initial load time

One of the most expensive types of assets in an app is JavaScript. Once the browser downloads a JavaScript file, it often has to decompress it, after that parse it, and finally execute it. That is why it’s critical for the performance of an app to ship fewer bytes of JavaScript during the initial load time. There are variety of practices we can apply to shrink our bundles. Two of the most popular ones are: There are variety of practices we can apply to shrink our bundles. Two of the most popular ones are:

  • Minification and dead code elimination
  • Code-splitting

The Angular CLI has been doing a great job minifying bundles and eliminating dead code. In version 8, the CLI also introduced differential loading support, which can reduce the amount of JavaScript for modern browsers even further. All this is completely automated by the tooling Angular provides. On the other hand, code-splitting is entirely in our hands. The next section is dedicated on how to shrink our JavaScript bundles by using this technique.

Code-splitting with Angular

  1. Component level code-splitting
  2. Route level code-splitting

The main difference between these two techniques is that with component level code-splitting, we can load individual components lazily even without a route navigation. For example, we can load the component associated with a chatbox only after the user clicks on a placeholder. With route level code-splitting, we load the individual routes lazily. For example, if the user is in the home page of an app and they navigate to the settings page, Angular will first download the corresponding bundle and after that render the route.

Component level code-splitting

Component level code-splitting has been hard in Angular because of the factories that the current version of the Angular compiler generates. The good news is that Ivy will enable simpler mechanism for it. In the future releases of the framework, we’ll work on using these capabilities to deliver ergonomic APIs for component level code-splitting. Until then, there are two community libraries you can use to achieve ergonomic code-splitting on a component level:

  1. ngx-loadable

  2. @herodevs/hero-loader

    Route-level code-splitting

Now let’s focus on route-level code-splitting. You can learn more about it here. This technique involves boilerplate code. To create a lazy route manually, we need to: With loadChildren,

  • declare a lazy route in a parent module

  • Generate a new component in the lazy loaded module

  • Declare an eager route declaration in the lazy module With Angular CLI version 8.1,

    you can now achieve this with a single command! To generate a lazy module use:

```ng g module [module name] --route [route name] --module [parent module]


For example:

ng g module ranking --route ranking --module app.module

The command above will:


- 
Generate a lazy-loaded module called RankingModule

- 
Insert a lazy route in app.module.ts

- 
Generate an eager default route inside the RankingModule

- 
Generate a component that will handle the eager default route
Once we introduce a lazy route in our app, when the user navigates to it, Angular will first download the corresponding bundle from the network. On a slow internet connection, this could lead to a bad UX.
To work around that, Angular provides router’s preloading strategy.

## Preloading Modules
There’s a built-in strategy that preloads all the modules in the application. You can use it by configuring the Angular router:

import { PreloadAllModules } from '@angular/router';

// ...

RouteModule.forRoot(ROUTES, { preloadingStrategy: PreloadAllModules })

// .. The risk with this strategy is that in an application with many modules, it may increase the network consumption and also block the main thread when Angular registers the routes of the preloaded modules.

For larger apps, we can apply more advanced preloading heuristics:

  • Quicklink — preload only modules associated with visible links in the viewport

  • Predictive prefetching — preload only the modules that are likely to be needed next

Performance budgets

To monitor our apps over time, the Angular CLI supports performance budgets. The budgets allow us to specify limits in which the production bundles of our app can grow. In the workspace configuration, under the budgets section, we can specify several different types of budgets:

Efficient serving

Looking at datasets of a lot of Angular apps running into the wild, we noticed that over 25% of them do not use content compression. Even more, don’t use a Content Delivery Network (CDN). These are two easy wins that are very simple to implement as part of the deployment pipeline. To allow developers to ship fast Angular apps from end-to-end as part of Angular CLI version 8.3 we’ll introduce a new command called deploy. By simply running ng deploy, you’ll be able to:

Conclusion

In this post we looked at few practical approaches to speed up an Angular app. We saw how to reduce the size of our JavaScript bundles using component-level and route-level code-splitting. As the next step, we discussed preloading strategies that can speed up page navigation. To monitor our app’s performance over time we introduced performance budgets. Finally, we talked about efficient serving and the integration of CDN and content compression enabled cloud services with the Angular CLI.