Angular Tips: Dynamic Module Imports with the Angular CLI
In typical Angular applications, we can lazy load code via the Angular Modules and the Angular Router. The router 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 load code on demand lazily? 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",
"types": []
},
"exclude": [
"src/test.ts",
"**/*.spec.ts"
]
}
Changing this setting configures the TypeScript compiler to use the latest ECMAScript / JavaScript module features. Now that we have everything set let's 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. Let's 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 let's take a look at the running example.
In our example, we reload the Angular app can see the immediate dependencies load. Once loaded the app can be used. In our case, we click the reverse button and can immediately see the lazily 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!