Loading optimization is one of the most crucial topics in the Front-End field, and it’s no surprise—applications need to be fast to deliver a great user experience. One effective way to speed up loading times is by reducing the application size, and lazy-loading is a key technique to achieve this. Most developers are familiar with how lazy-loading works: it's commonly used in all modern Front-End frameworks to split applications by routes and load components only when needed. Another widely used method is dynamic imports. However, these techniques can be challenging to implement in certain scenarios. In this article, I’ll explore these scenarios and discuss how to address them in Angular 17.
In my current application, there’s a significant amount of hidden content, such as tooltips and popups. While this isn’t a problem when the content is just text, it becomes a performance issue when it involves complex business features spread across the entire application. For instance, one of the tooltips is 320KB, filled with heavy components and services, all of which are required by the business. Additionally, these components are initialized multiple times in data tables—up to 100 times per table. The irony is that these components are often invisible until the user hovers over the tooltip, yet they still slow down the application. Most of the time, all we need to show is the text, not the hidden content. Before Angular 17, there wasn’t a convenient way to handle this, but now we have a powerful new tool: @defer
. Let’s take a look at the code below:
<!-- info-popup.html -->
<span
[pTooltip]="tooltipContent">
<ng-content></ng-content>
</span>
<ng-template #tooltipContent>
@defer {
<some-heavy-component></some-heavy-component>
}
</ng-template>
<!-- usage example -->
<info-popup>
<span>I'm a label for the heavy tooltip</span>
</info-popup>
In my current project, I use the PrimeNG library, which serves as the primary UI framework. PrimeNG is an excellent package with comprehensive documentation, making it a solid choice for building applications. In this solution, I use the [pTooltip]
directive to create tooltips and pass references to templates. Additionally, I pass content externally, which is then rendered as the label for the tooltip. Within the template, I utilize the @defer
directive, which enables lazy-loading of components. Specifically, <some-heavy-component>
is only loaded when the user hovers over the span
element. This technique significantly reduces the initial loading size and improves overall performance by minimizing the load time. By deferring the loading of heavy components until they are actually needed, we can achieve a much more efficient and responsive application.
I can't share the results just yet, as we're still in the implementation stage (we have enormous scenarios like this, and it will take some time to fully migrate to the new approach). We haven't run performance tests at this point, but it's important to remember that every project has its own unique stack and performance characteristics. What works well for us might yield different results in your specific context.
However, I hope you found this article insightful and that it encourages you to explore and adopt the new features of Angular. While your outcomes may vary, these techniques have the potential to bring significant improvements to your project's performance.