Lazy Loaded Module Example in Angular 8|7 with loadChildren & Dynamic Imports
Lazy loading is the process of loading some features of your Angular application only when you navigate to their routes for the first time.
Use asynchronous routing, which loads feature modules lazily, on demand. This can significantly reduce the initial load time of your application.
You now need to use the dynamic import syntax to import your module in the loadChildren property of Angular Router routes.
Angular provides the loadChildren property of a route’s path to specify the module that needs to be lazy loaded when it’s first navigated to.
we have been working with has 2 modules.
1.Root application module – AppModule
2.Feature module – EmployeeModule
app.module.ts
|
V
app-route.module.ts -> '',home,**
|
V
employee.module.ts
|
V
employee-route.module.ts -> list, create, edit/:id
we use asynchronous routing, which loads feature modules lazily, on demand. This can significantly reduce the initial load time of your application.
At the moment, the 2 modules (AppModule & EmployeeModule) in our application are eagerly loaded.
We want to lazily load EmployeeModule. To lazy load a module, it has to meet 2 requirements.
1.All the routes in an angular module that you want to lazy load should have the same route prefix.
2.The module should not be referenced in any other module. If it is referenced, the module loader will eagerly load it instead of lazily loading it.
use loadChildren property for lazy loading
{ path: 'employees', loadChildren: './employee/employee.module#EmployeeModule' }
#EmployeeModule – feature module class that we want to lazy load
Using loadChildren to Lazy-Load your Module – Angular 8
const routes: Routes = [
{ path: 'admin', loadChildren: () => import(`./employee/employee.module`).then(m => m.EmployeeModule) },
];
employee-routing.module.ts
const appRoutes: Routes = [
{
path: 'employees', //component less route.
children: [
{ path: '', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },
]
}
];
Code explanation :
- Notice we have a parent route with path employees
- The parent ‘employees‘ route has 3 child routes
- All the 3 child routes will be pre-fixed with the parent route path – employees
- Notice the parent route(employees) does not have a component associated with it. That is why this route is called a component less route.
- With the above route configuration, we have the following routes
/employees – Displays the list of all employees
/employees/create – Allows to create a new employee
/employees/edit/1 – Allows to create a edit an existing employee
1. app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';
const appRoutes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'employees', loadChildren: './employee/employee.module#EmployeeModule' }
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(appRoutes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule { }
2.employee-routing.module.ts
import { NgModule } from '@angular/core';
// Import RouterModule & Routes type
import { RouterModule, Routes } from '@angular/router';
// Import all the components that we will be referencing in the route definitions
import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';
/*
const appRoutes: Routes = [
{
path: 'employees',
children: [
{ path: '', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },
]
}
];
*/
//After you remove the 'employees' parent route, the routes should look as shown below.
const appRoutes: Routes = [
{ path: 'list', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },
];
// In a feature module forChild() method must be used to register routes
// Export RouterModule, so the it's directives like RouterLink, RouterOutlet
// are available to the EmployeeModule that imports this module
@NgModule({
imports: [ RouterModule.forChild(appRoutes) ],
exports: [ RouterModule ]
})
export class EmployeeRoutingModule { }
At this point, if we navigate to any of the EmployeeModule routes (“i.e /employees or employees/create or employees/edit/2”), we see either an empty page or the PageNotFoundComponent template displayed.
But if we include an extra “/employees” in the path as shown below, then all the EmployeeModule routes work as expected
/employees/employees
/employees/employees/create
/employees/employees/edit/2
To fix this, in “employee-routing.module.ts” file, change the following routes. We do not need the parent route – ’employees’.
After you remove the ’employees’ parent route, the routes should look as shown below.
const appRoutes: Routes = [
{ path: '', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },
];
BrowserModule provides services that are essential to launch and run a browser application. BrowserModule should be imported only once and that too only by the root module.
Angular Modules – Without Lazy Loading
app.module.ts
|
V
employee.module.ts --> employee-route.module.ts -> list, create, edit/:id
app-route.module.ts -> '',home,**
1.app.module.ts
@NgModule({
declarations: [
AppComponent,
HomeComponent,
PageNotFoundComponent
],
imports: [
BrowserModule,
EmployeeModule,
AppRoutingModule,
HttpClientModule,
],
providers: [EmployeeService],
bootstrap: [AppComponent]
})
export class AppModule { }
2. app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home.component';
import { PageNotFoundComponent } from './page-not-found.component';
const appRoutes: Routes = [
{ path: 'home', component: HomeComponent },
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: PageNotFoundComponent }
];
@NgModule({
imports: [ RouterModule.forRoot(appRoutes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule { }
Similarly ReactiveFormsModule is also not required in the root module. ReactiveFormsModule components, directives and pipes are only needed in EmployeeModule so we moved it there
3.employee.module.ts
import { NgModule } from '@angular/core';
// Exports all the basic Angular directives and pipes
// such as NgIf, NgFor, DecimalPipe etc.
import { CommonModule } from '@angular/common';
// CreateEmployeeComponent uses ReactiveFormsModule directives such as
// formGroup so ReactiveFormsModule needs to be imported into this Module
// An alternative approach would be to create a Shared module and export
// the ReactiveFormsModule from it, so any other module that needs
// ReactiveFormsModule can import it from the SharedModule.
import { ReactiveFormsModule } from '@angular/forms';
// Import the EmployeeRoutingModule
import { EmployeeRoutingModule } from './employee-routing.module';
// Import and declare the components that belong to this Employee Module
import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';
@NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
// Add EmployeeRoutingModule to the imports array
EmployeeRoutingModule
],
declarations: [
CreateEmployeeComponent,
ListEmployeesComponent
]
// If you want the components that belong to this module, available to
// other modules, that import this module, then include all those
// components in the exports array. Similarly you can also export the
// imported Angular Modules
// exports: [
// CreateEmployeeComponent,
// ReactiveFormsModule
// ]
})
export class EmployeeModule { }
4.employee-routing.module.ts
import { NgModule } from '@angular/core';
// Import RouterModule & Routes type
import { RouterModule, Routes } from '@angular/router';
// Import all the components that we will be referencing in the route definitions
import { CreateEmployeeComponent } from './create-employee.component';
import { ListEmployeesComponent } from './list-employees.component';
// Define the routes
const appRoutes: Routes = [
{ path: 'list', component: ListEmployeesComponent },
{ path: 'create', component: CreateEmployeeComponent },
{ path: 'edit/:id', component: CreateEmployeeComponent },
];
// In a feature module forChild() method must be used to register routes
// Export RouterModule, so the it's directives like RouterLink, RouterOutlet
// are available to the EmployeeModule that imports this module
@NgModule({
imports: [ RouterModule.forChild(appRoutes) ],
exports: [ RouterModule ]
})
export class EmployeeRoutingModule { }
RouterModule forRoot vs forChild
forRoot() method registers the specified routes. It also creates an instance of the Router service and registers it with the angular’s dependency injector.
forChild() method on the other hand only registers the additional specified routes and tells angular to reuse the Router service instance that forRoot has created.
Angular services are singletons.
So, to ensure that, there is only one instance of Router service, forRoot() method should be called only once in the main application routing module.
In all the feature routing modules forChild() method should be used to register the additional routes. When the forChild() method is called, Angular Router knows it has to only register the additional specified routes and not to re-register the Angular Router service.
angular-lazy-load-module-example
lazy-loading-in-angular
lazy-loading-in-angular-slides