TL; DR: Lazy loading in Angular improves app performance by loading modules only when needed. This reduces initial load time and improves user experience.
Angular is a globally used framework for building extremely complex and high-performing web applications at scale. However, as your app grows, performance issues might start to show if you haven’t designed your Angular app properly.
As a result, many developers use lazy loading when developing production-level Angular apps. This technique reduces the size of data transferred over the network by breaking the build bundle into smaller chunks and helps the app respond quickly. This article will guide you through implementing lazy loading for Angular and compare the loading times to show the performance gain.
Syncfusion® Angular component suite is the only suite you will ever need to develop an Angular application faster.
Understanding lazy loading in Angular
Angular uses its routing system for lazy loading. When a user initially starts the app, it will only load the AppModule or any other starting module you have defined. Then, as the user navigates through the app, Angular will check the route and load the module related to that route on demand. Here are the benefits of this approach:
- Faster initial load times: By loading only the required parts at the beginning, your app works faster.
- Reduced bundle size: Breaking your app into smaller parts makes the first download smaller, which helps users with slow internet connections.
- Improved performance for large apps: As your app grows, lazy loading keeps the load time fast by loading one feature at a time.
- Better user experience: When pages load faster, and navigation is easier, users are more satisfied and engaged.
Implementing lazy loading with Angular
Let’s walk through the process of implementing lazy loading in an Angular app. We’ll create a simple project with multiple feature modules to demonstrate this concept.
Prerequisites
- Install Node.js
- Install Angular CLI
npm install -g @angular/cli
Verify the installation by running the following command:
ng version
Use the right property of Syncfusion® Angular components to fit your requirement by exploring the complete UG documentation.
Step 1: Creating a new Angular project
Create a new Angular app using the following command:
ng new lazy-loading-demo --no-standalone --routing
In the wizard, you will get a prompt to select the preferred styling format. For this example, I have selected CSS.
Navigate to the project using the below command:
cd lazy-loading-demo
Step 2: Serve the application
Start the development server to ensure everything is set up correctly:
ng serve
Open your browser and go to http://localhost:4200/ to see your new Angular app running.
Step 3: Lazy loading implementation
Create a new Angular module and a component for lazy loading:
ng generate module image-gallery --route image-gallery --module app.module
Then, update the image-gallery.component.ts file with the following code.
import { Component } from '@angular/core'; @Component({ selector: 'app-image-gallery', templateUrl: './image-gallery.component.html', styleUrls: ['./image-gallery.component.css'] }) export class ImageGalleryComponent { imageUrls: string[] = []; ngOnInit(): void { this.loadImages(); } loadImages(): void { this.imageUrls = [ // Add Image Urls here ]; } }
Update the image-gallery-routing.module.ts file to set up the routing for the lazy-loaded module:
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { ImageGalleryComponent } from './image-gallery.component'; const routes: Routes = [{ path: '', component: ImageGalleryComponent }]; @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] }) export class ImageGalleryRoutingModule { }
Update the image-gallery.module.ts file to include the component and routing module.
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ImageGalleryRoutingModule } from './image-gallery-routing.module'; import { ImageGalleryComponent } from './image-gallery.component'; @NgModule({ declarations: [ ImageGalleryComponent ], imports: [ CommonModule, ImageGalleryRoutingModule ] }) export class ImageGalleryModule { }
Step 4: Configuring lazy loading in the main app
Now, update your app-routing.module.ts file to include the lazy-loaded route.
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ { path: 'images', loadChildren: () => import('./image-gallery/image-gallery.module').then(m => m.ImageGalleryModule) }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
Make sure the AppRoutingModule is imported into the main app.module.ts file.
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; @NgModule({ declarations: [ AppComponent, ], imports: [ BrowserModule, AppRoutingModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
Step 5: Updating the app module
Now, update the app.component.html file with the following code to include navigation.
<div class="image-gallery"> <div class="image-item" *ngFor="let imageUrl of imageUrls"> <img [src]="imageUrl" alt="Image"> </div> </div>
Step 6: Testing the Lazy-Loaded modules
Start the app using the ng serve command and navigate to http://localhost:4200 in your browser.
To ensure your lazy loading implementation is effective, it’s crucial to measure and optimize performance:
- Lighthouse: This tool in Chrome DevTools gives a complete report on performance. It includes measures like First Contentful Paint and Time to Interactive.
- Angular CLI: Use ng build –prod –stats-json Run webpack-bundle-analyzer to see your bundle composition.
- Bundle size analysis: Tools such as source-map-explorer help identify large modules that may get a performance boost by lazy loading.
- DevTools: A browser extension that provides insight into your app structure and performance.
Be amazed exploring what kind of application you can develop using Syncfusion® Angular components.
Performance measurement and optimization
With lazy loading
Without lazy loading:
As you can see, there’s a clear difference between the bundle sizes with and without lazy loading.
- With lay loading – 1.41 kB
- Without lazy loading – 2.79 kB
You might not see a massive difference here since the app is small. But, as your app grows, these numbers will significantly impact its app performance.
Potential optimizations
While this basic implementation demonstrates lazy loading, there are further optimizations you can consider:
- Preloading: Angular offers strategies to preload lazy-loaded modules during idle times.
- Route-level code splitting: For large feature modules, consider splitting them into smaller, lazy-loaded child routes.
- Common module: Extract shared components and services into a common module to avoid duplication.
Remember, performance optimization is an iterative process. Regularly measure your app’s performance, implement optimizations, and re-measure to ensure continuous improvement.
Challenges
When using lazy loading in Angular, developers might face some common problems. Here are some of the most common issues and how to fix them:
Module not found errors
Module not found errors are generally caused by a wrong path for a lazy-loaded module or a missing module file.
Error
- Console error: ERROR Error: Uncaught (in promise): Error: Cannot find module ‘path/to/module’.
- The lazy-loaded route fails to load.
Troubleshooting
- Double-check the path in your route configuration.
- Ensure the module file exists at the specified location.
- Verify that the module name in the loadChildren function matches the actual module name.
- Check for any typos in file names or paths.
Circular dependency warnings
Circular dependencies may affect lazy loading and the performance of an app as a whole.
Error
- Console warning about circular dependency.
- Unexpected behavior in lazy-loaded modules.
Troubleshooting
- Check your module structure for circular imports.
- You should refactor your code to break the circular dependency.
- Move shared services to a separate module.
- Use the forward reference where appropriate.
- You may want to try using a forwardRef() function for dependencies that are more difficult to decouple.
Route configuration problems
Incorrect routing configurations can prevent lazy-loaded modules from functioning.
Error
- One or more lazy-loaded routes are inaccessible.
- 404 when trying to navigate to lazy-loaded routes.
Troubleshooting
- Verify that the lazy-loaded module has not been imported into the main AppBundle.
- Ensure that RouterModule.forRoot() is absent from the lazy-loaded module and only RouterModule.forChild() is present.
- Verify that your routes in the lazy-loaded module are correctly defined without conflicts.
- Ensure the loadChildren property is correctly set up in the route configuration of the parent module.
Additional tips
- Apply Angular CLI commands like ng generate module to create well-structured lazy-loaded modules.
- Seek out Angular’s built-in tooling-for example, the –prod flag while building-allows for possible lazy loading problems to be detected.
- Keep your Angular version updated so there will be improvements and fixes for lazy loading problems.
GitHub repository
If you wish to check out the full code, explore my GitHub repository.
Harness the power of feature-rich and powerful Syncfusion® Angular UI components.
Conclusion
Lazy loading delays loading parts of the app until they are required. This reduces network data transfer since you don’t have to load everything at once, which ultimately speeds up the loading process.
If you are planning to start a new project, I highly recommend you follow this guide and design it based on lazy loading from scratch. If you already have an existing project, you can start by finding parts in your current projects that could use lazy loading and slowly implementing this method.
Thank you for reading!