DEV Community

Cover image for Angular 9: Lazy Loading Components

Angular 9: Lazy Loading Components

John Papa on February 16, 2020

Angular 9 has some pretty awesome new features. The runtime, code-name Ivy, opens the doors to things like making lazy load Angular components more...
Collapse
 
coly010 profile image
Colum Ferry

Given that we can lazy load components in their own, where is our use case to do so?

Right now, I feel like it doesn't fit well.

We mount the components to the ViewContainerRef, but do we not lose the ability to style where the lazy component gets mounted.

Take for example a page that contains a login form.

We don't necessarily want that visible until the user clicks a Sign In button on our page. Once we do this, then we lazy load the LoginFormComponent.

But if we're just mounting to a ViewContainerRef, how exactly do we style that the login form should maybe show in an in-line div under the Sign In button the user clicked?

Collapse
 
john_papa profile image
John Papa

Good questions. I planted the seeds of some of these same questions in the last section of this article. Perhaps lazy components can be most helpful when you need to load components dynamically. Which ones should load? Based on user roles? Based on some workflow or profile rules?

The login component you mention could contain its own styles.

Collapse
 
coly010 profile image
Colum Ferry • Edited

I'll admit I do like the thought of having the ability in the future to dynamically load components based around more complex logic in our TS rather than bloating our HTML with it.

It paves the way for BuilderComponents that can generate views based on what information we pass to it.

Think of taking FormBuilder one step further to FormBuilderComponent where we give it our FormGroup and it renders the appropriate form controls based on the structure of our FormGroup.

My gripe right now is that, yes, our dynamically loaded component can style itself, but it does not currently have the ability to style where it lives/renders in its parent and its parent loses its ability to style where its dynamic children render.

With Content Projection using ng-content, we at least maintain the ability to decide where our children get rendered and how the area surrounded them gets styled.

Thread Thread
 
layzee profile image
Lars Gyrup Brink Nielsen • Edited

This ASP.NET-style school of thought was part of the original Angular 2 design doc, but features such as FormLayoutComponent never made the final cut, neither did built-in state management and quite a few other features.

Collapse
 
filini profile image
Filippo Gualandi • Edited

I tried to use this approach to dynamically change which component is loaded with a selector, like this:
ng-template selector="my-component"
I know this is not a "you should do this" article, but...
I feel like the loss of declarative input/output is a bit limiting.

Collapse
 
layzee profile image
Lars Gyrup Brink Nielsen

Take a look at NGX Dynamic. It could probably be combined with dynamic imports to get lazy-loaded components with property and event bindings.

Collapse
 
filini profile image
Filippo Gualandi

Thank you for the suggestion, I had already checked npmjs.com/package/ng-dynamic-compo... which looks similar. Unfortunately, the declarative option in NGX Dynamic is deprecated.

To give you a bit more context on my "experiments": I am developing an app that needs to be customized by delivery teams. Customization will mostly be view changes. My idea is to put the biggest part of the code in an external npm module (so that updates/fixes are released via npm), then if the delivery team wants to change some component, they can simply load another component with the same selector.

Since delivery teams are usually composed of junior devs, I would really like to give them a view markup that is as "standard" as possible, hence my hope to do something like this (deprecated in NGX Dynamic):
<ng-template selector="my-component" [input]="myInput" (output)="myOutput()">

Anyway, I will probably end up putting the HTML views in the distributed code, not on npm, but dynamic component loading is a very interesting topic for me :)

Thread Thread
 
layzee profile image
Lars Gyrup Brink Nielsen

Did you consider letting them pass in templates and rendering them using ngTemplateOutlet?

Collapse
 
zombierobo profile image
Hasmukh Suthar

For people wondering what’s the use case of lazy loaded components, a good example is a pdf file download button. Rather than preloading the client side pdf maker library, we can embed the pdf maker library in a lazy loaded component which gets instantiated on click of download button. This reduces the size of chunk file that renders the page and delays fetching of the library chunk file until it is actually used.

Collapse
 
vitale232 profile image
Andrew Vitale

That's def a good use case for the apps we're building at work!

I came across this article that uses some newer web pack features and a service to achieve the same effect. It works great in an app with a more traditional "feature module" architecture. Maybe it's useful for you

medium.com/javascript-in-plain-eng...

Collapse
 
layzee profile image
Lars Gyrup Brink Nielsen • Edited

John, we can use feature render modules to use child components in the template instead of this imperative approach. We should remember to pass the injector along to the embedded views to enable dependency injection.

An upcoming alternative to ViewContainerRef#createComponent is renderComponent.

Collapse
 
layzee profile image
Lars Gyrup Brink Nielsen • Edited

Another way to switch from an imperative approach to a declarative approach is to use *ngComponentOutlet instead of ViewContainerRef#createComponent.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
layzee profile image
Lars Gyrup Brink Nielsen

Here's an alternative take. Lazy-loaded routed components without Angular modules, using the Angular Router:
github.com/LayZeeDK/ngx-lazy-loade...

Collapse
 
john_papa profile image
John Papa

Cool - thanks for sharing!

Collapse
 
bergermarko profile image
Marko Berger

I would really like to lazyload a component with my angular element. Don't think is possible but it would be so cool.