Initial loader in Angular app done properly

Wojciech Trawiński
JavaScript everyday
3 min readMay 21, 2020

I’ve recently spent a lot of time learning about web performance 🏫. I became quite familiar with the concept of the Critical Rendering Path and render-blocking resources. In this post, I would like to present a proper approach to displaying a spinner while an Angular application is loading 🎠.

Exemplary app

The test application simply imports the Bootstrap CSS portion and the Moment.js library just to get some content in the final bundles 📦, namely 143 KB and 462 KB respectively. You can find the source code here (the final solution is on the async-css branch).

In order not to display a blank screen until the Angular is ready to render some content, you can put a very simple spinner between the app-root element:

Note that it’s just the standard index.html file generated by the Angular CLI with some additional content.

The idea is to simply render the loader which ships 🚢 immediately with the index.html instead of a blank screen. At first sight it may seem to be a good solution, but … let’s dive in 🔍!

Synchronous CSS

You can play around with the test app (on the master branch). If you run the server script, the app gets built and is being served by the http-server. If you slow down the network 🐌, you can notice that the behavior is as follows:

  • the page is blank until CSS gets fetched,
  • the loader gets rendered,
  • when all the scripts get parsed, compiled and executed, the Angular is ready to kick in and render the content.

The problem is that the screen is blank until the style sheet is available. The reason is that CSS is a render-blocking resource and a browser has to wait until CSSOM is created in order to build a render tree and fill pixels on the screen 📺. As a result, a user keeps waiting for the CSS in front of a blank page and you can take advantage of rendering the spinner only while Angular is getting ready. Let’s take a look at how to improve the behavior with the concept of asynchronous CSS loading.

Asynchronous CSS

If you do not want to treat a CSS file as a render-blocking resource, you need to replace such tag:

with this one:

In short, you can use a browser hint (rel=”preload”) to instruct it to fetch the resource. Once it’s been loaded, you change the rel attribute value so that the style sheet is taken into account when computing CSSOM. The resource is no longer a render-blocking, therefore the spinner gets rendered immediately 🎆. You can read more about it here.

Hook into build process

The question is how to instruct the Webpack to create an asynchronous version of the link once it’s generated the standard index.html file. Luckily, you can make use of custom Webpack builders for Angular 🚂. Netanel Basal has written a great blog post on how to hook it up into the Angular. In a nutshell, you need to update a builder in the angular.json file 📄 and add appropriate options. If you want to update an index.html, you should do the following:

The index-html-transform.js simply exports a function that will be called with the initial index.html file. The goal is to find the link tag and grab the href attribute out of it. Next, you need to insert the async link version at the end of the head section and get rid of the initial sync link tag:

I hope you liked the post and learned something new 👍 If so, please give me some applause 👏

--

--