DEV Community

Cover image for Angular Design Pattern-Lazy loading feature modules
Jagadeesh Musali
Jagadeesh Musali

Posted on • Edited on

Angular Design Pattern-Lazy loading feature modules

Introduction

By default, angular modules are eagerly loaded, which means that all feature modules are loaded as soon as the application loads whether or not they are immediately necessary.

Why

For large applications with lots of routes, user might not visit all of them frequently. So loading required modules on demand helps keep initial bundle sizes smaller, which in turn helps decrease load times.

How it is with eager loading

Assuming you have an application with a feature module(Itemsmodule). This is how your application routes looks like with an Eager loading design pattern.

If you look at below code, its basically telling Angular to load ItemComponent on the screen whenever user navigates to /items

const routes: Routes = [
  { path: 'items', component: ItemComponent }
];
Enter fullscreen mode Exit fullscreen mode

And you would have ItemsModule under imports of AppModule

app.module.ts

const routes: Routes = [
  { path: 'items', component: ItemComponent }
];

@NgModule({
  declarations: [AppComponent],
  imports: [
    ItemsModule,
    RouterModule.forRoot(routes)
  ]
})
export class AppModule {
  constructor() {}
}
Enter fullscreen mode Exit fullscreen mode

With this, ItemsModule will be loaded as soon as the application loads.

How it would be with lazy loading

Now lets look how this can be done with lazy loading design pattern.

To lazy load Angular modules, use loadChildreninstead of component in your routes configuration as shown below.

Notice that the lazy-loading syntax uses loadChildrenfollowed by a function that uses the browser's built-in import('...')syntax for dynamic imports. The import path is the relative path to the module.

const routes: Routes = [
  {
    path: 'items',
    loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  }
];
Enter fullscreen mode Exit fullscreen mode

And you would then remove itemsModulefrom app.module.ts as we no longer loading it on initial load.

app.module.ts

const routes: Routes = [
  {
    path: 'items',
    loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
  }
];
@NgModule({
  declarations: [AppComponent],
  imports: [
    RouterModule.forRoot(routes)
  ]
})
export class AppModule {
  constructor() {}
}
Enter fullscreen mode Exit fullscreen mode

Looks confusing? it does at first, but all its telling to Angular is, "whenever user visits /items only then load itemsModule"

Now, there is one more step to understand, so far we have only loaded itemsModule at app.module.ts level. We are yet to mention which component in itemsModule has to be loaded when user visits /items.

To do that, we have to go inside the feature module(itemsModule) to mention which component to load.

items.module.ts

const routes: Routes = [
  {
    path: '',
    component: ItemComponent
  }
];
@NgModule({
  imports: [ RouterModule.forChild(routes) ]
})
export class ItemsModule {
  constructor() {}
}
Enter fullscreen mode Exit fullscreen mode

The path here is set to an empty string because the path in AppRoutingModule is already set to /items.

Every route in this feature module is a child route.

So if you need something like /items/frequent, you just have to define that child route inside feature module like shown below.

items.module.ts

const routes: Routes = [
  {
    path: '',
    component: ItemComponent
  },
{
    path: '/frequent',
    component: FrequentComponent
  }
];
@NgModule({
  imports: [ RouterModule.forChild(routes) ]
})
export class ItemsModule {
  constructor() {}
}
Enter fullscreen mode Exit fullscreen mode

So now, /items takes user to ItemComponentand /items/frequent takes user to FrequentComponent

yay!!! Now you understood Lazy loading design pattern. Angular docs have an excellent detailed explanation on this topic. I would recommend to read it.

For a sample application with two lazy-loaded modules see the live example taken straight out of Angular docs.

Top comments (3)

Collapse
 
achebrol profile image
Azeet Chebrolu

Nice article Jag👍

Collapse
 
layzee profile image
Lars Gyrup Brink Nielsen

Nice article, thank you for writing it.

Shouldn't ItemsModule use RouterModule.forChild? Otherwise, non-tree-shakable router providers such as the Router service will have duplicate instances.

Collapse
 
jagadeeshmusali profile image
Jagadeesh Musali

Correct. Its my mistake while editing post. It should be forChild. Thanks for pointing. I have corrected it.