This article is for versions of Angular 2, Angular 4 and later.

In typical Angular applications we can lazy load code via the Angular Modules and the Angular Router. This is a great way to lazily load features as need and reduce our JavaScript payloads increasing application performance. In the latest version of TypeScript (2.4) we get a new way to lazy load code: Dynamic Module Imports.

JavaScript and TypeScript both implement the static module syntax as shown below:



import { Component, Input, OnInit } from '@angular/core';


This is great for organizing code but what if we want to lazily load code on demand? This is where the new JavaScript dynamic import feature comes in. The Dynamic Import syntax is as follows:




if (myCondition === true) {
  import('/common/helpers/string').then(stringHelpers => {
    stringHelpers.reverse('Hello World');
  });
}



The Dynamic Imports allow us to load our code on demand asynchronously. The API is promise based. We pass in a string path of where the module is located. When the code has loaded the module reference is passed into the then function for us to access.

This is a great way to load code deterministically. Maybe only in certain situations we want to load the code based on user actions.

Configuring the Angular CLI project

In our Angular CLI projects we have to do a bit more work to enable this feature in our projects. First we need to check the package.json to check a few package versions. The Angular CLI version should be on 1.2 or later. Then towards the bottom of the dependencies list the typescript package should be on 2.4 or later. Finally Angular itself should be on 4.2 or later. Update these packages first and rerun npm install.

Once completed we need to jump to the tsconfig.app.json inside the /src directory of our project. Update the module property from es2016 to use esnext like so:




{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "module": "esnext",
    "baseUrl": "",
    "types": [
      "google.analytics",
      "openlayers",
      "webpack-env"
    ]
  },
  "exclude": [
    "test.ts",
    "../build/**",
    "**/*.spec.ts"
  ]
}



Changing this setting configures the TypeScript compiler to use the latest ecmascript / JavaScript module features. Now that we have everything configured lets try it out!

Using Dynamic Imports

In our example we will create a simple button that when clicked will load our module on demand and execute a function. For this example we will display a string on the app component and when a button is clicked the string helpers module will be loaded with a simple reverse string utility function. Lets look at the component code below.




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

@Component({
  selector: 'app-root',
  template: `
    My name {{name}}
    <button (click)="reverse()">Reverse</button>
  `
})
export class AppComponent {
  name = 'Cory Rylan';

  reverse() {
    import('./string-helpers').then(module => {
      this.name = module.reverseString(this.name);
    });
  }
}



In our app component when the button is clicked the component method loads the reverse string function using the dynamic import syntax. Once the module is loaded in our promise we reverse the string of the name property on the component. Below is the code in the string-helpers module.




export function reverseString(input: string) {
  return input.split('').reverse().join('');
}



Now lets take a look at the running example.

In our example we reload the Angular app can can see the immediate dependencies load. Once loaded the app can be used. In our example we click the reverse button and can immediately see the lazy loaded module be downloaded in the Chrome Network Panel. Once loaded we can execute the reverse string function as many times as we want and our app will keep the module in memory and not load it again.

Dynamic imports a powerful and welcome tool to have in our JavaScript applications. Check out the full working Angular CLI demo below!

Demo