Introduction
Today, in this article, we will discuss the most significant features of Angular Framework i.e. Feature Modules. With the help of Angular Framework, we can develop both large-scale based application or small scale based application. Actually, with the help of Angular Modules, we can be designed our application into a part of different modules so that we can manage the application in a much better way. Since, if we use one single block or module for our application, then when the application starts growing to incorporate the new features and functionalities, it becomes a tedious job to manage the entire mode under a single block or module. In the same place, if we use multiple modules or blocks, then the maintenance of the code is easier. In this way, we can incorporate the new functionality or features in a new module and then include that module in our application.
So, there are many possible ways to group the functionalities into modules and the decision always depends upon the developers to find the best way for the application. So, when we break the application into multiple modules, then it becomes one of the important responsibilities of developers to maintains all modules so that performance of the application can be boosted up. We can break the application into multiple modules and then import all modules references into the bootstrapped module. The result of this approach will be that application loading will be slow as the application size increases. So, the best approach is that break the application into multiple modules as a Feature Module which can provide the following benefits:
- It will avoid the loading of the entire application at a time.
- Can be pre-loaded the features modules in the background
- Lazy load of the feature modules on demand means when the user wants to access that module or related functionality then only that particular module will be loaded into the DOM.
So, in this article, we will discuss the concept of Feature Modules and the Lazy loading of a Feature Module and also demonstrate how to implement this concept into any Angular Application.
What are Feature Modules in Angular?
So, in Angular Framework, a Feature Module is simply an Angular module with module related kinds of stuff and purpose. But the main difference is that is not the root module of the application. Feature module is just an additional typescript based class with the @NgModule decorator and registered metadata. Feature modules isolate the applications based on the functionality or business operation and it collaborates with the root modules or any other feature modules. The main purpose of the feature modules is to break down the functionality which focuses on any particular internal business operation or functionality that needs to be dedicated as a module so that we can achieve modularity in the application. With the help of feature modules, we also can restrict the responsibility of the root modules and help the root module to keep it thin and small.
In general, we can define five different types of feature modules in an application – Domain, Routed, Routing, Service, and Widget. Each of these types of feature module concentrates and provides specific types of utilities.
- Domain Feature Modules – This type of feature module is based on the application navigation like Product or Product feature modules.
- Routed Feature Modules – All the lazy loaded modules are known as routed modules.
- Routing Feature Modules – This type of feature module is based on the routing and its related functionality based like Route Guards.
- Service Feature Modules – The service feature module mainly acts as a utility module related to the API request-response. This feature is mainly imported in the root module. It is mostly used for the data messaging API request-response.
- Widget Feature Modules – This feature module is based on the Widget related modules which may contain utility, pipes, directive, etc.
Every feature module always has the following functionalities:
- We can declare a separate set of Components, Directives, and Pipes for the feature modules.
- We can also export the feature module just like another angular module so that other angular modules can consume its component, directives, and pipes.
- Feature modules can provide services to itself and other modules also.
- The feature module can import other angular modules into its module and use its components, directives, and pipes.
Benefits of Feature Modules
Now, in the above section, we discuss the concept of Feature module in any Angular application. So, before going to implement or demonstrate the feature module, we first need to understand what the benefits of feature module implementations are:
- The feature module always helps us to define clear separation for the features.
- With the help of the feature module, we can organize the code and structure in a much better way. It will always help us to decouple the non-related functionality and features.
- In the case of a feature module, the module can be used lazy loaded modules. Lazy loaded modules will help in creating scalable applications.
- The feature module always follows the SOC (Separation of Concern) principle. It helps us to separate the feature and code responsibility.
- With the help of Lazy-loading functionality, the initial load time of the application can be reduced. Angular has preload features that load the module still not loading it completely.
- Practically we can do everything with the root module, say app module in our case. Putting everything in the root module pollutes the root module. Feature module provides a set of functionality, flow, and forms focused on application needs.
What is Lazy Loading of Modules?
The lazy loading technique is not a new one introduced by the Angular Framework. It is a process or method to download the data on-demand, say, for example, Documents, JavaScript files, CSS, Images, and Videos in small pieces. This process or method normally performs the data loads operations in chunks instead of bigger pieces to improve the performance of the application.
Normally, we already included all the feature modules within the root module with the help of the import statement. So, when the application starts, all the files related to the modules defined or imported within the root modules will be downloaded first and then the application loading will be completed. If that file size is large, then application initial loading will take time since it will be complete only when the downloading part is complete. This type of loading is normally known as eager loading.
The standard import syntax in eager loading is always static. That’s why it always evaluated all code at the load time. In this circumstance, if we want to load a particular module conditionally or on-demand, then we need to use the dynamic import instead of static import. This dynamic import concept is normally known as the Lazy loading of angular modules. With the help of Lazy loading, we can shrink the size of the application as only required modules will be loaded by the browser at the startup. The rest of the modules will be downloaded and loaded dynamically on-demand concept.
Benefits of Lazy Loading Modules
So, as per the Angular Framework, if we are using the eager loading technique, then if the application consists of many or a large number of components, it will take a long time to load all components when an app is a download. Due to this, the user experience related to the application will be degraded. So, if we consider that first impressions are the last impressions in case of any application, then it will be a very serious issue. So, to overcome this limitation of eager loading, Angular Framework has introduced the Lazy Loading strategy. In this process, it loads only those components which are required to render the page. So, it saves time and renders the application much faster than the eager loading. Lazy loading also has many benefits, such as:
- It loads only those components which are required to render within the page.
- It loads the application much faster compared to the eager loading.
- It helps us to improve the user experience.
Steps to Perform Feature Module with Lazy Loading in Angular Applications
Now, it's time to demonstrate how we can implement Feature Modules with Lazy Loading in any angular application. For that purpose, we are going to develop one application which contains the Top 10 Player details for different sports. The final output of the application is just like below:
For that purpose, first, we create an Angular Project with the help of Angular CLI as per the below folder structure:
Now, we add the below code in the files, as shown in the above structure:
app.component.css
- h1 {
- font-size: 3em;
- color: #999;
- margin-bottom: 0;
- }
-
- h2 {
- font-size: 2em;
- margin-top: 0;
- padding-top: 0;
- color:crimson;
- }
-
- nav a {
- padding: 5px 10px;
- text-decoration: none;
- margin-top: 10px;
- display: inline-block;
- background-color: #eee;
- border-radius: 4px;
- }
-
- nav a:visited, a:link {
- color: #607D8B;
- }
-
- nav a:hover {
- color: #039be5;
- background-color: #CFD8DC;
- }
-
- nav a.active {
- color: #039be5;
- }
app.component.ts
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.css']
- })
- export class AppComponent {
- title = 'Angular Feature Module Demo';
- }
app.component.html
- <h1>{{title}}</h1>
- <nav>
- <a routerLink="/home" routerLinkActive="active">Home</a>
- <a routerLinkActive="active">Cricket</a>
- <a routerLinkActive="active">Football</a>
- <a routerLinkActive="active">Tenis</a>
- </nav>
- <br>
- <router-outlet></router-outlet>
home.component.ts
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'home-page',
- template: `
- <div>
- <h2>Demonstration of Feature Modules with Lazy Loading Concept</h2>
- </div>
- `,
- styleUrls: ['./app.component.css']
- })
- export class HomeComponent {
-
- }
app.module.ts
- import { BrowserModule } from '@angular/platform-browser';
- import { NgModule } from '@angular/core';
-
- import { AppRoutingModule } from './app-routing.module';
- import { AppComponent } from './app.component';
- import { HomeComponent } from './home.component';
-
- @NgModule({
- declarations: [
- AppComponent, HomeComponent
- ],
- imports: [
- BrowserModule,
- AppRoutingModule
- ],
- providers: [],
- bootstrap: [AppComponent]
- })
- export class AppModule { }
app-routing.module.ts
- import { NgModule } from '@angular/core';
- import { Routes, RouterModule } from '@angular/router';
- import { HomeComponent } from './home.component';
-
- const routes: Routes = [
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'home', component: HomeComponent },
-
- ];
-
- @NgModule({
- imports: [RouterModule.forRoot(routes)],
- exports: [RouterModule]
- })
- export class AppRoutingModule { }
Now, execute the program and check the output in the browser:
So, we have already defined the root module in the application. Now, it's time to define the feature module. First, we will define one feature module called FootballModule which mainly contains the information related to football. So, for that purpose, we create a folder called football under the app folder and add the below files. We define another angular module which contains all the related files required to define a module.
football.component.css
- [class*='col-'] {
- float: left;
- padding-right: 20px;
- padding-bottom: 20px;
- }
-
- [class*='col-']:last-of-type {
- padding-right: 0;
- }
-
- a {
- text-decoration: none;
- }
-
- *, *:after, *:before {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- }
-
- h3 {
- text-align: center;
- margin-bottom: 0;
- }
-
- h4 {
- position: relative;
- }
-
- .grid {
- margin: 0;
- }
-
- .col-1-4 {
- width: 25%;
- }
-
- .module {
- padding: 20px;
- text-align: center;
- color: rgb(14, 1, 1);
- max-height: 120px;
- min-width: 120px;
- background-color: #7ef7a6;
- border-radius: 2px;
- }
-
- .module:hover {
- background-color: #EEE;
- cursor: pointer;
- color: #607d8b;
- }
-
- .grid-pad {
- padding: 10px 0;
- }
-
- .grid-pad > [class*='col-']:last-of-type {
- padding-right: 20px;
- }
-
- @media (max-width: 600px) {
- .module {
- font-size: 10px;
- max-height: 75px;
- }
- }
-
- @media (max-width: 1024px) {
- .grid {
- margin: 0;
- }
-
- .module {
- min-width: 60px;
- }
- }
football.component.html
- <h2>
- <a href="https://www.ea.com/games/fifa/fifa-20/ratings/fifa-20-player-ratings-top-100">
- Football - Top 10 Player (FIFA Ranking)
- </a>
- </h2>
- <div class="grid grid-pad">
- <a *ngFor="let data of footballData" class="col-1-4">
- <div class="module hero">
- <h4>{{data.name}}</h4>
- </div>
- </a>
- </div>
football.component.ts
- import { Component, OnInit } from '@angular/core';
-
- @Component({
- selector: 'football-info',
- templateUrl: './football.component.html',
- styleUrls: ['./football.component.css']
- })
- export class FootballInfoComponent implements OnInit {
- public footballData:Array<any>=[];
-
- constructor() {
-
- }
-
- ngOnInit(): void {
- this.footballData = [
- { id: 1, name: 'Lionel Messi' },
- { id: 2, name: 'Cristiano Ronaldo' },
- { id: 3, name: 'Neymar Jr.' },
- { id: 4, name: 'Eden Hazard' },
- { id: 5, name: 'Kevin De Bruyne' },
- { id: 6, name: 'Jan Oblak' },
- { id: 7, name: 'Virgil Van Dijk' },
- { id: 8, name: 'Mohamed Salah' },
- { id: 9, name: 'Luka Modrić' },
- { id: 10, name: 'Marc-André ter Stegen' }
- ];
- }
- }
football.home.component.ts
- import { Component } from '@angular/core';
-
- @Component({
- selector: 'football-home',
- template: '<router-outlet></router-outlet>'
- })
- export class FootballHomeComponent {
-
- constructor() {
- }
- }
football.module.ts
- import { NgModule } from '@angular/core';
- import { CommonModule } from '@angular/common';
- import { FormsModule, ReactiveFormsModule } from "@angular/forms";
-
- import { FootballRoutingModule } from './football.routing.module';
- import { FootballHomeComponent } from './football.home.component';
- import { FootballInfoComponent } from './football.component';
-
- @NgModule({
- imports: [
- CommonModule,FormsModule, ReactiveFormsModule,
- FootballRoutingModule
- ],
- declarations: [
- FootballHomeComponent, FootballInfoComponent
- ],
- entryComponents:[
- FootballInfoComponent
- ],
- bootstrap:[FootballHomeComponent]
- })
- export class FootballModule {
-
- }
football.routing.module.ts
- import { NgModule } from '@angular/core';
- import { RouterModule, Routes } from '@angular/router';
-
- import { FootballHomeComponent } from './football.home.component';
- import { FootballInfoComponent } from './football.component';
-
- const routes: Routes = [
- {
- path: '',
- component: FootballHomeComponent,
- children: [
- { path: 'top10fifa', component: FootballInfoComponent},
- ]
- }
- ];
-
- @NgModule({
- imports: [
- RouterModule.forChild(routes)
- ],
- exports: [
- RouterModule
- ]
- })
- export class FootballRoutingModule {
- }
Now, we define the Football feature module. After it, in the root routes we need to use loadChildren to introduce the lazy loading with the help of the import function.
- import { NgModule } from '@angular/core';
- import { Routes, RouterModule } from '@angular/router';
- import { HomeComponent } from './home.component';
-
- const routes: Routes = [
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'home', component: HomeComponent },
- {
- path: 'football',
- loadChildren: () => import('./football/football.module').then(module => module.FootballModule)
- }
- ];
-
- @NgModule({
- imports: [RouterModule.forRoot(routes)],
- exports: [RouterModule]
- })
- export class AppRoutingModule { }
LoadChildren is a method that will be executed only when we need to access that particular route. Only at that time, this particular module will be loaded into the DOM. For that we will provide the related routerlink against the link text:
- <h1>{{title}}</h1>
- <nav>
- <a routerLink="/home" routerLinkActive="active">Home</a>
- <a routerLinkActive="active">Cricket</a>
- <a routerLink="/football/top10fifa" routerLinkActive="active">Football</a>
- <a routerLinkActive="active">Tenis</a>
- </nav>
- <br>
- <router-outlet></router-outlet>
Now, check the output in the browser:
If we inspect the application with the browser’s Network tab, we will see that when we click on the football link then only football module related js file is download in the browser. If the files are download once, then it will not download again until we close the browser or reload the main application.
Similarly, we can create Cricket and tennis football with the same types of functionality and then include them in the app routing module as child modules. Also, the Angular framework provides another technique called Preloading Strategy for the Lazy loading module concept. In this process, app routes first load the route related component to render the page as quickly as possible. After the first route loading complete, it starts loading the other modules as a background process. In this way, other modules will be ready automatically, and the user does not need to wait for a load of all the components of that module. To implement the preloading strategy, we just need to include that into the root route module as below,
- import { NgModule } from '@angular/core';
- import { Routes, RouterModule, PreloadingStrategy, PreloadAllModules } from '@angular/router';
- import { HomeComponent } from './home.component';
-
- const routes: Routes = [
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'home', component: HomeComponent },
- {
- path: 'cricket',
- loadChildren: () => import('./cricket/cricket.module').then(module => module.CricketModule)
- },
- {
- path: 'football',
- loadChildren: () => import('./football/football.module').then(module => module.FootballModule)
- },
- {
- path: 'tenis',
- loadChildren: () => import('./tennis/tennis.module').then(module => module.TennisModule)
- },
- ];
-
- @NgModule({
- imports: [RouterModule.forRoot(routes, {
- preloadingStrategy : PreloadAllModules
- })],
- exports: [RouterModule]
- })
- export class AppRoutingModule { }
So, now when we check the application loading in the browser tab, we will see that when the application load at the time feature module related files already downloaded.
Conclusion
So, Feature Module and Lazy Loading are some of the essential features in any application. When we use these in any application, it affects many other things like user experience, performance, bootstrapping an application, etc. With the help of some extra configuration setting, it will provide us a lot of benefits in any application. I hope, this article will help you to understand the basic concept of feature modules and lazy loading. Also, help you to implement these functionalities in an Angular Application. Any feedback or query related to this article is most welcome.