Introduction
Lazy loading is an approach to limit the modules that are loaded to the ones that the user currently needs. This can improve your application’s performance and reduce the initial bundle size.
By default, Angular uses eager loading to load modules. This means that all the modules must be loaded before the application can be run. While this may be adequate for many use cases, there may be situations where this load time begins to affect performance.
Note: The following covers lazy loading modules in Angular 8+ apps.
In this article, you will use lazy loading routes in an Angular application.
Prerequisites
To complete this tutorial, you will need:
Node.js installed locally, which you can do by following How to Install Node.js and Create a Local Development Environment.
Some familiarity with setting up an Angular project.
This tutorial was verified with Node v16.4.0, npm
v7.19.0, @angular/core
v12.1.0, and @angular/router
v12.1.0.
Step 1 – Setting Up the Project
Lazy loaded routes need to be outside of the root app module. You will want to have your lazy loaded features in feature modules.
First, let’s use Angular CLI to create a new project with Angular Router:
ng new angular-lazy-loading-example --routing --style=css --skip-tests
Then navigate to the new project directory:
cd angular-lazy-loading-example
Let’s create a new feature module:
ng generate module shop --route shop --module app.module
Now let’s also create 3 components inside our shop
feature module:
The first will be a cart
component:
ng generate component shop/cart
The second will be a checkout
component:
ng generate component shop/checkout
The third will be a confirm
component:
ng generate component shop/confirm
All three components will be located in the shop
directory.
Note: Do not import feature modules that should be lazy-loaded in your app module, otherwise they will be eager loaded.
At this point, you should have a new Angular project with a shop
module and 3 components.
Step 2 – Using loadChildren
In your main routing configuration, you will want to do something like the following:
src/app/app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [
{ path: 'shop', loadChildren: () => import('./shop/shop.module').then(m => m.ShopModule) },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
New with Angular 8, loadChildren
expects a function that uses the dynamic import syntax to import your lazy-loaded module only when it’s needed. The dynamic import is promise-based and gives you access to the module, where the module’s class can be called.
Step 3 – Setting Route Configuration in the Feature Module
Now all that’s left to do is to configure routes specific to the feature module.
Here’s an example:
src/app/shop/shop-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CartComponent } from './cart/cart.component';
import { CheckoutComponent } from './checkout/checkout.component';
import { ConfirmComponent } from './confirm/confirm.component';
const routes: Routes = [
{ path: '', component: CartComponent },
{ path: 'checkout', component: CheckoutComponent },
{ path: 'confirm', component: ConfirmComponent },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class ShopRoutingModule { }
And finally, in the feature module itself, you’ll include your routes with RouterModule
’s forChild
method instead of forRoot
:
shop/shop.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ShopRoutingModule } from './shop-routing.module';
import { ShopComponent } from './shop.component';
import { CartComponent } from './cart/cart.component';
import { CheckoutComponent } from './checkout/checkout.component';
import { ConfirmComponent } from './confirm/confirm.component';
@NgModule({
declarations: [
ShopComponent,
CartComponent,
CheckoutComponent,
ConfirmComponent,
],
imports: [
CommonModule,
ShopRoutingModule
]
})
export class ShopModule { }
Now you can use the routerLink
directive to navigate to /shop
, /shop/checkout
, or /shop/confirm
and the module will be loaded the first time one of these paths are navigated to.
In your terminal, start the server:
ng serve
This will generate a main.js
file and a src_app_shop_shop_module_ts.js
file:
Initial Chunk Files | Names | Size
vendor.js | vendor | 2.38 MB
polyfills.js | polyfills | 128.58 kB
main.js | main | 57.18 kB
runtime.js | runtime | 12.55 kB
styles.css | styles | 119 bytes
| Initial Total | 2.58 MB
Lazy Chunk Files | Names | Size
src_app_shop_shop_module_ts.js | - | 10.62 kB
Next, use your browser to visit localhost:4200
.
Verify that lazy loading works by opening the browser’s DevTools and looking at the Network tab. When the application initially loads at the application root, you should not observe lazy chunk files. When you navigate to a route like /shop
, you should observe src_app_shop_shop_module_ts.js
.
Note: If it is not working right away, try restarting your server.
Your application now supports lazy loading.
Conclusion
In this article, you used lazy loading routes in an Angular application.
Continue your learning with testing components with dependencies, testing services as well as using mocks, stubs, and spies.
You can also refer to the official documentation for more information on lazy loading.