In this article, we are going to take a look at a feature introduced in Ionic 4 that will reduce the initial load times of our applications. Before we get into discussing that, though, I want to highlight that when it comes to performance we can't just rely on the framework.
I published an article earlier this week that discusses this. The main point of the article is that improvements to the performance of the framework are not all that important if you haven't already optimised the code in your application. There are usually far bigger performance gains to be made by improving your code, compared to upgrading to a faster version of a framework. A well designed Ionic application today can already boot very fast and operate smoothly, small optimisations like the lazily loaded web components that we will be discussing in this article are just icing on the cake. If your cake isn't made well then it doesn't really matter how much icing you have.
If you feel that your applications are not as fast as they could be, then you may find value in reading the article: Ionic Framework Is Fast (But Your Code Might Not Be)
Lazy loading is a general concept where we only load things as we need them. You may already be familiar with lazy loading Angular components (i.e. the pages in your Ionic application). In Ionic 3, we would use
@IonicPage to lazy load our pages, and now with Ionic 4 we lazy load our Angular components with Angular routing. The idea behind lazy loading pages is that we don't need to load every page in the application as soon as the application is launched.
Lazy loading web components in Ionic 4 takes this a step further. In Ionic 4, every Ionic component that we use is a web component. Each of these web components will be lazily loaded only when they are accessed in the application.
This means that the code for
<ion-card> will only be loaded when it is accessed in the application, even each
<ion-icon> is loaded individually rather than having to load the entire icon library. This isn't even something we need to set up, it is just the way it works by default.
In the rest of this article, I will be demonstrating how this works, and how it compares to Ionic 3. I will be comparing production builds of the Ionic conference application – we will be taking a look at both the Ionic 3 and Ionic 4 (alpha) branches of this application. The Ionic conference application is a good example to use, as it is a reasonably complex application maintained by the Ionic team.
We will be using the Network tab to observe the behaviour of the web components. We will compare the overall load time between the Ionic 3 and Ionic 4 (alpha) versions, but that is not the main purpose of this experiment. Ionic 4 is still in alpha, and this post is not intended to be some kind of benchmark performance comparison between Ionic 3 and Ionic 4. This is just one specific example, and the primary purpose is to observe how lazy loaded web components behave.
To perform this experiment, I have cloned the Ionic conference app and have checked out the
core-update branch. We will be taking two measurements using the Network tab in the browser debugging tools, we will observe:
- What is loaded initially, and the overall load time
- What is loaded when transitioning to another page.
Here is what the initial load looks like:
We can see a bunch of files that have been loaded in, but take note of how we can see individual icons (and specifically the
md material design icons for Android) being loaded in. We can see that
md-information-circle are being loaded, all of which are used specifically on this page.
In total, we have 432KB of data being transferred and a load time of 1.22 seconds. Now let's see what happens when we clear the network requests, and click on the About tab:
We have another 16.9KB of content being transferred over 8 requests. The effect is clearer to see on this page as we don't have all of the other initial startup requests clogging up the network tab, now we can more clearly see how individual requests are being made to load individual web components. It is easy to see the icons being loaded in because they are listed in the network tab as
md-iconname, but the other components like the date picker, and the popup used for the location input are also being loaded in lazily (these are the
avhv6nzq.js style requests you can see).
Now, let's see what the network tab looks like when we use the Ionic 3 version:
This time, we have 489KB of data being transferred and a load time of 1.40 seconds. We can see that the Ionic 4 load time was faster, but I don't think the specific page load times here are all that interesting, as I mentioned, this is just one small specific test and isn't a very scientific way to compare performance.
These examples also aren't making full use of lazy loading components – at the time of writing this, the current example for the Ionic 4 tabs application does make some use of lazy loading, but the various tab pages are not being lazily loaded. If you are interested in learning about how to lazy load tabs in an Ionic 4 application you should read Creating a Tabs Layout with Angular Routing and Ionic 4.
Let's take a look at what I think is the interesting part of this experiment. If we once again clear the network tab and click on the About tab, we would see this:
We can clearly see the effect of lazy loading (or rather, lack of lazy loading) here. We can see network requests for the image and font, but the components that are available on this page are not being loaded in as they are accessed. All of these components have already been loaded upfront.
Lazy loading allows us to load what we need when we need it. The ability to lazy load each individual web component just takes what we have been doing previously to lazy load Angular components to another level, where we can even just load individual icons as we need them.
By only loading in what we need as we need it, we reduce the amount of upfront work the application needs to do, which will lead to faster startup times. And the best part is we don't need to do anything fancy to enable this… it just happens by default!