Angular module inline lazy loading
August 04, 2023
What do I mean with inline lazy loading in Angular. There is regular lazy loading for entire modules based on the route:
Angular Docs - Lazy loading feature modules. In most of the cases this is enough, as
the entire module and components are only loaded by the browser once the user navigates to the given route.
However, in specific edge cases you might want to lazy load a component on the same page independent of a router navigation,
for example when it’s hidden with an *ngIf
or if it’s the content of a dialog.
Let’s say we have a component MyBigComponent
@Component({
selector: 'my-big-component',
template: 'template content',
})
export class MyBigComponent {}
and it is registered in our module MyBigModule
@NgModule({
imports: [],
exports: [MyBigComponent],
declarations: [MyBigComponent],
})
export class MyBigModule {
public getComponent() {
return MyBigComponent;
}
}
Note:
- usually you don’t have any logic within module classes, but in this case we actually need the
getComponent
method. - make sure that you do not load the module or the component in any of your regular
imports
declarations because then everything will already be added to the same bundle and not in a separate one
Now comes the fun part. In the place where you want the lazy loaded content to be visible include
<ng-template #content></ng-template>
And now we just need a method to load the content into the ng-template
element.
class RandomPageComponent {
@ViewChild('content', { read: ViewContainerRef }) public content!: ViewContainerRef;
constructor(private injector: Injector) {}
public async loadContent() {
const { MyBigModule } = await import('./my-big.module');
const moduleRef = createNgModule(MyBigModule, this.injector);
const lazyComponent = moduleRef.instance.getComponent();
this.content.clear();
this.content.createComponent(lazyComponent, { ngModuleRef: moduleRef });
}
}
If you now call the loadContent
method, for example on a button click (click)="loadContent()"
your component will be rendered in the browser.
But the code for it will actually be in a separate chunk file. You can check this if you open the network tab in your dev tools before you click the button.
This works similar if you want to have this working for a dialog. You can just create a DialogContentComponent
and call the loadContent
in your OnInit
function.
How does it work
ng-template
The <ng-template>
is an element that by default is not rendered in the browser and you need to specifically instruct Angular
to render it (ng-template docs).
In our case we get the template element with @ViewChild
and then call methods like clear()
to remove every currently existing content
and then createComponent
to fill it with the content we want.
await import
This is probably the most crucial part to this entire snipped. Usually our imports are at the top. However, if we use it inline in a function, this
will tell the Angular CLI to not include the code right here, but to create a separate chunk JavaScript file and only have the reference in the
loadContent
method. This will cause the chunk file only to be loaded by the browser once this reference is being called.
createNgModule
The createNgModule
create a module reference. This is needed if your component actually uses any service injections or other modules.
With the Injector
service we get from the constructor we can pass it in as parent injector and make sure that the context stays
within our current scope.
getComponent
This is the function we added earlier to the module, returning the class (not an instance!) of our component that we want to render.
Then we just need to stitch everything together, call the createComponent
method from our ng-template
and pass it the component class and the
module reference and an instance of our component will be created and rendered inside the ng-template
.
Personal Blog written by Nicolas Gehlert, software developer from Freiburg im Breisgau. Developer & Papa. Github | Twitter
Add a comment
Comments
Oleh
August 23, 2024
I have been working with Angular since the very beginning, but I have never seen anything like this. Excellent solutions and presentation of material. Your articles are sometimes better than Medium. Now I work only with your advice. Thank you.