Lazy Loading Feature Modules in Angular

As Angular applications grow larger, they often include multiple features, pages, and components. Loading all of these modules at once can lead to slow application startup and negatively impact user experience. To address this challenge, Angular provides a mechanism called lazy loading, which allows modules to be loaded on demand rather than at startup.

Lazy loading improves performance, reduces the initial bundle size, and organizes large applications effectively. In this comprehensive guide, we will cover:

  • Introduction to lazy loading in Angular
  • Benefits of lazy-loaded modules for app performance
  • Step-by-step configuration of lazy-loaded routes using loadChildren
  • Best practices for using lazy loading in Angular applications

What Is Lazy Loading?

Lazy loading is a design pattern where certain parts of the application, such as feature modules, are loaded only when they are needed, rather than during the initial application startup. In Angular, lazy loading is implemented using feature modules and the Angular Router.

Key Features of Lazy Loading

  1. On-Demand Module Loading: Modules are fetched only when users navigate to routes that require them.
  2. Smaller Initial Bundle: Reduces the size of JavaScript that the browser downloads at startup.
  3. Improved Performance: Faster initial load times and better user experience.
  4. Separation of Concerns: Feature modules remain isolated and self-contained, improving maintainability.

Why Lazy Loading Improves Performance

Without lazy loading, Angular bundles all modules into a single JavaScript file by default. For small apps, this is fine, but for larger applications, it can create longer load times:

  • Large bundle size → slower first paint
  • Users may never need all features immediately
  • Initial load performance becomes critical for mobile users

Lazy loading addresses these issues by:

  • Loading only essential modules initially
  • Fetching feature modules on-demand as users navigate
  • Reducing memory usage and network consumption

Prerequisites for Lazy Loading

Before implementing lazy loading, ensure:

  1. Your application uses Angular Router.
  2. Features are organized into modules (feature modules).
  3. Feature modules are self-contained and optionally include their own routing module.

Step-by-Step Guide to Configuring Lazy-Loaded Modules

Step 1: Generate a Feature Module

Use Angular CLI to create a feature module:

ng generate module products --route products --module app.module

Explanation:

  • products → Name of the module
  • --route products → Automatically sets up a route for lazy loading
  • --module app.module → Adds configuration in the root module

This generates:

src/app/products/
 ├─ products.module.ts
 ├─ products-routing.module.ts
 └─ components/ (optional components)

Step 2: Structure the Feature Module

products.module.ts example:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ProductsRoutingModule } from './products-routing.module';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductDetailComponent } from './product-detail/product-detail.component';

@NgModule({
  declarations: [
ProductListComponent,
ProductDetailComponent
], imports: [
CommonModule,
ProductsRoutingModule
] }) export class ProductsModule { }
  • declarations → Components specific to this feature
  • imports → CommonModule and ProductsRoutingModule for routing

Step 3: Set Up Feature Module Routing

products-routing.module.ts example:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductDetailComponent } from './product-detail/product-detail.component';

const routes: Routes = [
  { path: '', component: ProductListComponent },
  { path: ':id', component: ProductDetailComponent }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class ProductsRoutingModule { }
  • RouterModule.forChild(routes) sets up routes specific to the feature module
  • Root module doesn’t need to know about individual components of the feature module

Step 4: Configure Lazy Loading in App Routing

Update app-routing.module.ts:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  { path: '', redirectTo: 'home', pathMatch: 'full' },
  { path: 'home', loadChildren: () => import('./home/home.module').then(m => m.HomeModule) },
  { path: 'products', loadChildren: () => import('./products/products.module').then(m => m.ProductsModule) },
  { path: '**', redirectTo: 'home' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
  • loadChildren uses dynamic imports to load modules on demand
  • Arrow function returns a promise that resolves to the module class
  • Angular automatically bundles the module separately for lazy loading

Step 5: Verify Lazy Loading

  1. Run the application:
ng serve
  1. Open the Network tab in browser dev tools.
  2. Navigate to /products. You should see a separate chunk loaded dynamically.

Example: Lazy Loading Multiple Feature Modules

Suppose your app has Products and Orders features:

const routes: Routes = [
  { path: 'products', loadChildren: () => import('./products/products.module').then(m => m.ProductsModule) },
  { path: 'orders', loadChildren: () => import('./orders/orders.module').then(m => m.OrdersModule) }
];
  • Both modules are lazy-loaded
  • Only loaded when users navigate to /products or /orders

Benefits of Lazy Loading

  1. Reduced Initial Load Time
    • Only essential modules are loaded initially
  2. Better Performance for Large Apps
    • Keeps the main bundle small
  3. Organized Architecture
    • Feature modules remain isolated and self-contained
  4. Improved User Experience
    • Faster first paint and less waiting for users

Advanced Lazy Loading: Preloading Strategy

Angular allows preloading of lazy-loaded modules to balance initial load and navigation speed.

imports: [RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })]
  • Preloads lazy modules in the background after app loads
  • Reduces delay when navigating to lazy-loaded routes

Lazy Loading Best Practices

  1. Organize Features into Modules
    • Only modules that can be loaded independently should be lazy-loaded
  2. Avoid Lazy Loading Tiny Modules
    • Lazy loading introduces a slight overhead; don’t lazy-load very small modules
  3. Keep Routing Self-Contained
    • Use RouterModule.forChild() inside feature modules
  4. Use Preloading for Large Apps
    • Improves user experience for routes that are likely to be visited
  5. Combine with Shared Modules
    • Feature modules can import a SharedModule for common components and directives

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *