Lazy loading Recipes 🚀

🥱 🔃 🍳

Pankaj P. Parkar

Senior Technology Consultant, Virtusa

  • MS MVP

  • Angular GDE

  • Opensource Maintainer

  • Stackoverflow Topuser

About Me!

What is Lazy Loading?

It is technique of loading relevant resources on demand

pankajparkar

Lazy Loading Recipes

  1. Lazy loading routes
  2. Dynamic Component Loading
  3. Import + SCAM
  4. Possible Future 😲 🎁

pankajparkar

1. Lazy loading routes

Application Architecture

App Module

Dashboard Module

Admin Module

Product Module

Roles Module

import

import

import

import

pankajparkar

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent },
  { path: 'roles', component: RolesComponent },
  { path: 'admin', component: AdminComponent },
  { path: 'product', component: ProductComponent },
  { path: '**', redirectTo: 'dashboard' },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    ...materialModules, BrowserAnimationsModule, BrowserModule, 
    AppRoutingModule, SharedModule,
    // loading modules eagerly
    AdminModule, DashboardModule, ProductModule, RolesModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Application Routing

const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule)
  },
  { 
    path: 'roles',
    loadChildren: () => import('./roles/roles.module').then(m => m.RolesModule)
  },
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  },
  {
    path: 'product',
    loadChildren: () => import('./product/product.module').then(m => m.ProductModule)
  },
  {
    path: '**',
    redirectTo: 'dashboard'
  },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

App Module

Dashboard Module

Admin Module

Product Module

Roles Module

Module level Lazy Loading

pankajparkar

path: dashboard

path: admin

path: product

path: roles

import { PreloadingStrategy, Route } from '@angular/router';

import { Observable, of } from 'rxjs';

export class CustomPreloadStrategy implements PreloadingStrategy {
    preload(route: Route, load: Function): Observable<any> {
        return route.data && route.data.preload ? load() : of(null);
    }
}

Custom Preload Strategy

const routes: Routes = [
  {
    path: 'dashboard',
    loadChildren: () => import('./dashboard/dashboard.module')
		.then(m => m.DashboardModule)
  },
  { 
    path: 'roles',
    loadChildren: () => import('./roles/roles.module').then(m => m.RolesModule),
    data: { preload: true }, //<-- Added information here
  },
  ...
];

2. Dynamic Component Loading

@ViewChild('container', { read: ViewContainerRef }) container: any;

constructor(
) { }

async addBarComponent() {
  this.container.clear();
  const componentRef = this.container.createComponent(BarChartComponent);
}

clear() {
  this.container.clear();
}
<button (click)="addBarComponent()">
    Show Barchart Component
</button>
<ng-container #container></ng-container>

pankajparkar

Weather Forecast Widget

pankajparkar

Source - https://github.com/pankajparkar/weather-cast

Import + SCAM

 (Single Component Angular Module)

@Component({
  selector: 'wc-weather-dashboard',
  ...
})
export class WeatherDashboardComponent {
  @Input() headingStart = 'Weather Forecast in';
  ...
}
@NgModule({
  declarations: [
    WeatherDashboardComponent,
    ...
  ],
  imports: [...],
  exports: [WeatherDashboardComponent]
})
export class WeatherForecastModule { }
import './weather-forecast.module';
export * from './weather-dashboard/weather-dashboard.component';

 (Single Component Angular Module)

@ViewChild('container', { read: ViewContainerRef }) container: any;

constructor(
  private factory: ComponentFactoryResolver
) { }

async loadWeatherWidget() {
  this.container.clear();
  const weatherComponent = await import('../weather-forecast')
	.then(i => i.WeatherDashboardComponent);
  const componentRef = this.container.createComponent(weatherForecastWidget);
  componentRef.instance.headingStart = 'Just for fun';
}
<button (click)="loadWeatherWidget()">
    Load Weather Widget
</button>
<ng-container #container></ng-container>

Import + SCAM

pankajparkar

Component Level Lazy Loading

App Module

Dashboard Module

Admin Module

Product Module

Roles Module

pankajparkar

Standalone Components on the way

Source - https://github.com/angular/angular/discussions/43784

pankajparkar

@Component({
  standalone: true,
  imports: [
    // Modules
    ...matModules,
    CommonModule,
    BrowserAnimationsModule,
    ReactiveFormsModule,
    FormsModule,
    // Other Standalone Components
    FiltersComponent,
    WeatherForecastComponent,
    WeatherForecastDetailsComponent,
    WeatherForecastCityComponent,
    WeatherForecastHistoryComponent,
  ],
  selector: 'wc-weather-dashboard',
  templateUrl: './weather-dashboard.component.html',
  styleUrls: ['./weather-dashboard.component.css']
})
export class WeatherDashboardComponent implements OnInit, OnDestroy {

  ...
  
}

Standalone Component

pankajparkar

RouterModule.forRoot([
  {
      path: 'weather-forecast', 
      loadComponent: () => import('../weather-component')
	.then(m => m.WeatherDashboardComponent)
  },
  {
      path: '/some/route/to/standalone/with/default/export', 
      loadComponent: () => import('./default-standalone.cmp')
  }
]);

Standalone Component (routing)

pankajparkar

Q & A

pankajparkar

pankajparkar

pankajparkar

References

Made with Slides.com