🅰️ Angular Q106 / 128

Explain Angular router preloading strategies.

AI-Powered Answer ✓ Answered

Angular's router supports lazy loading of modules, which means parts of your application are loaded only when they are needed. While lazy loading improves initial load times, subsequent navigation to a lazy-loaded route still involves a network request. Preloading strategies address this by loading lazy modules in the background after the initial application bootstrap, improving the user experience for subsequent navigations.

What is Preloading?

Preloading is a technique where lazy-loaded Angular modules are fetched from the server and processed by the browser in the background, shortly after the application's initial load. This happens before the user actually navigates to those routes, making subsequent navigations instantaneous as the modules are already available in the browser's memory.

Why Use Preloading?

  • Improves user experience by making subsequent navigations feel faster and more seamless.
  • Reduces perceived loading times for lazy-loaded sections of the application.
  • Optimizes resource utilization by loading modules during idle times.

Configuring Preloading

Preloading strategies are configured in the root module's RouterModule.forRoot() function.

typescript
import { RouterModule, Routes, PreloadAllModules } from '@angular/router';

const routes: Routes = [
  // ... your routes
];

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

Angular's Built-in Preloading Strategies

1. NoPreloading

This is the default strategy. It disables preloading for all lazy-loaded modules. Modules are loaded only when the user navigates to their routes.

typescript
RouterModule.forRoot(routes, { preloadingStrategy: NoPreloading })

2. PreloadAllModules

This strategy preloads all lazy-loaded modules immediately after the application has finished loading and bootstrapping. It ensures that all modules are ready when the user navigates to them, but it can consume more bandwidth and potentially delay initial app interactivity if too many modules are preloaded.

typescript
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })

Custom Preloading Strategies

For more fine-grained control, you can create a custom preloading strategy by implementing the PreloadingStrategy interface. This allows you to define your own logic for which modules to preload and when.

typescript
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

export class CustomPreloadingStrategy implements PreloadingStrategy {
  preload(route: Route, fn: () => Observable<any>): Observable<any> {
    // Your custom logic here
    if (route.data && route.data['preload']) {
      return fn(); // Preload this module
    } else {
      return of(null); // Do not preload this module
    }
  }
}

The preload method receives two arguments: * route: The route configuration object. * fn: A function that returns an Observable. If you want to preload the module associated with the route, you call and return the result of fn(). If not, you return of(null).

Example: Selective Preloading Strategy

A common custom strategy is to preload only specific modules. You can mark routes in their configuration with a custom data property.

typescript
const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
    data: { preload: true } // Mark for preloading
  },
  {
    path: 'reports',
    loadChildren: () => import('./reports/reports.module').then(m => m.ReportsModule)
    // No 'preload' data, so it won't be preloaded by this strategy
  }
];

Then, your custom preloading strategy would check this data property:

typescript
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, of } from 'rxjs';

export class SelectivePreloadingStrategy implements PreloadingStrategy {
  preload(route: Route, fn: () => Observable<any>): Observable<any> {
    if (route.data && route.data['preload']) {
      console.log('Preloading: ' + route.path);
      return fn();
    }
    return of(null);
  }
}

Finally, you provide and use your custom strategy:

typescript
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SelectivePreloadingStrategy } from './selective-preloading-strategy';

// ... routes definition

@NgModule({
  imports: [RouterModule.forRoot(routes, { preloadingStrategy: SelectivePreloadingStrategy })],
  exports: [RouterModule],
  providers: [SelectivePreloadingStrategy] // Provide your custom strategy
})
export class AppRoutingModule { }

Other Custom Preloading Scenarios

  • Network-Aware Preloading: Check network conditions (e.g., using navigator.connection.effectiveType) and preload only if the connection is fast enough.
  • User-Idle Preloading: Use a library like ngx-web-worker or custom logic to preload modules only when the user's browser is idle.
  • Preloading by User Role/Permissions: Preload modules relevant to the logged-in user's role.
  • Predictive Preloading: Based on user behavior analytics, predict which modules the user is likely to visit next and preload those.

Choosing the Right Strategy

StrategyDescriptionUse Case
NoPreloadingModules are loaded only when a user navigates to their routes (on-demand).Small applications, applications with very specific or rarely visited sections, or when initial bundle size and bandwidth are critical constraints.
PreloadAllModulesAll lazy-loaded modules are preloaded immediately after the application starts.Applications where most users will likely visit all sections, applications with good internet connectivity, or when the goal is the fastest possible subsequent navigation.
Custom StrategyAllows defining custom logic to decide which modules to preload and when.Complex applications, scenarios requiring optimized resource usage based on user behavior, network conditions, user roles, or specific business rules. (e.g., Selective Preloading, Network-Aware Preloading).