Boosting Angular’s Performance With Lazy Loading (Part 3)

Lazy loading modules are a great feature to incorporate in your projects and in most cases, the functionality is enough. But what happens when you are using non-routable modules? As a developer, you probably already know that component templates are not always fixed and you may need to dynamically create and load components at runtime. In part 3 of 3, we’ll guide you through a step by step solution for how to load dynamically, at runtime, a predefined set of modules and components in your application, all while taking advantage of the optimization benefits of using Ahead-of-Time compilation. For an introduction to what lazy loading is and some basic entry point tips, check out part 1. To Learn more about preloading strategies check out part 2.

How to Dynamically Load a Module

For this example, you will learn to dynamically load a module and render a programmatically created component. We’ll assume this module contains several components, directives, pipes and services and that this functionality is seldom used by the users of the app. Often, the module case, containing all the logic related to a dashboard editor, is where the user can select widgets, customize them and specify where they are shown. Adding this module to the main bundle is unnecessary because all the users would be forced to load it, although most of them will probably never need the feature. To have the option to only load the module when the user clicks on a button to access that section.

Let’s get to the coding.

To define the module mentioned above, create a dynamic-component. In this case, the code is the boilerplate from the ng generate component. In the module you’ll find a static property, indicating the root component, which you will use later to inject it in the view.


import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DynamicComponent } from './dynamic.component';

  declarations: [DynamicModule.rootComponent],
  bootstrap: [DynamicModule.rootComponent],
  imports: [
export class DynamicModule {
  static rootComponent = DynamicComponent;

Next, lazy load the module. Add the lazyModules array property to the app angular.json file. Angular then sends a request to Webpack instructing it to create an independent chunk, which after completion will lazy load the module. The compiler pre compiles every module defined in that array. Then it divides them into separate minified chunks, moving them to the SystemJS loader at runtime with Ahead Of Time compilation.


  "projects": {
    "lazyLoading": {
      "architect": {
        "build": {
          "options": {
            "lazyModules": [

Now, when you start running the npm you can see how Webpack extracts the dynamic-module, as well as its dependencies, to a separate chunk. Below is the console output.

Boosting Angular’s Performance with Lazy Loading - Part 3

Let’s load the modules. For routable modules, the router needs help from the SystemJsNgModuleLoader oader. Use it in the app by declaring AppModule:


import { BrowserModule } from '@angular/platform-browser';
import { NgModule, SystemJsNgModuleLoader, NgModuleFactoryLoader } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ModuleLoadDirective } from './module-load.directive';

  declarations: [
  imports: [
  providers: [
    { provide: NgModuleFactoryLoader, useClass: SystemJsNgModuleLoader }
  bootstrap: [AppComponent]
export class AppModule { }

Use custom directive to create a piece of code, which is used by the loader to load the module.

To accomplish this, create a provider to define the lazy load modules map. This acts as an object, defining all the modules and their paths.

Here the InjectionToken comes in handy, acting as a factory function, which can be injected later on in the directive, returning it to the proper value.


import { InjectionToken } from '@angular/core';

export type LAZY_DYNAMIC_MODULES = {
  dynamicModule: string;

export const lazyDynamicMap: LAZY_DYNAMIC_MODULES = {
  dynamicModule: 'src/app/dynamic/dynamic.module#DynamicModule'

export const LAZY_DYNAMIC_MODULES_MAP = new InjectionToken('LAZY_DYNAMIC_MODULES_MAP', {
  factory: () => lazyDynamicMap

Now comes defining the directive, where all the magic happens. What the custom directive does is it takes the module name as an input, loads the module and injects the root component, previously defined in the module to the current ViewContainerRef.


import { Directive, OnInit, OnDestroy, Input, NgModuleRef, Injector, Inject, NgModuleFactory, NgModuleFactoryLoader, Type , ViewContainerRef} from '@angular/core';
type ModuleWithRoot = Type<any> & {rootComponent: Type<any>};

  selector: '[appModuleLoad]'
export class ModuleLoadDirective implements OnInit, OnDestroy {
  @Input('appModuleLoad') moduleName: keyof LAZY_DYNAMIC_MODULES;
  private ngModuleRef: NgModuleRef<any>;

    private viewContainerRef: ViewContainerRef,
    private injector: Injector,
    private ngModuleFactoryLoader: NgModuleFactoryLoader,
    @Inject(LAZY_DYNAMIC_MODULES_MAP) private modulesMap
  ) {}

  ngOnInit() {
      .then((moduleFactory: NgModuleFactory<any>) => {
        this.ngModuleRef = moduleFactory.create(this.injector);
        const rootComponent = (moduleFactory.moduleType as ModuleWithRoot).rootComponent;
        const factory = this.ngModuleRef.componentFactoryResolver.resolveComponentFactory(


  ngOnDestroy() {
    this.ngModuleRef && this.ngModuleRef.destroy();

The last step is to include the directive in the main template and add a button to display it.


<div style="text-align:center">
    Welcome to {{ title }} example!
  <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">

<ng-container *ngIf="showDynamic" appModuleLoad="dynamicModule"></ng-container>
<button (click)="showDynamic=!showDynamic">Load dynamic</button>

Browser Result

See below the first loading page.

Boosting Angular’s Performance with Lazy Loading - Part 3

After the “load dynamic” button is clicked, the dynamic-module is loaded and the dynamic component rendered.

Boosting Angular’s Performance with Lazy Loading - Part 3

Now It's Your Turn

As this three-part article series comes to a close, we hope you enjoy trying out these features in your future coding. With the combined knowledge of the two previous articles, your lazy loading repertoire should help give you more custom control over your loading times. We recommend taking full advantage of each lazy loading scenario!

Building Credibility and Influence as a Leader: John Sadler with Agilent Technologies
Listen to episode