Introduction
Angular applications can suffer from performance issues as they grow in complexity. Two critical techniques for optimizing Angular applications are Lazy Loading of modules and strategic management of Change Detection. This tutorial provides an in-depth exploration of these concepts with practical implementations.
Learning Objectives: – Master lazy loading architecture – Implement optimized change detection strategies – Improve application load time and runtime performance – Advanced debugging and optimization techniques
Prerequisites: – Basic Angular understanding (Components, Modules, Services) – TypeScript proficiency – Node.js (v16+) and npm installed
Tools & Technologies: – Angular CLI (v15+) – Chrome DevTools – Webpack Bundle Analyzer
Estimated Completion Time: 90 minutes
Fundamentals and Core Concepts
Key Terminology
- Lazy Loading: Loading feature modules on-demand
- Change Detection: Angular's mechanism to update DOM
- NgModule: Logical boundary for application features
- Route Configuration: Defines navigation paths
Change Detection Explained
Angular uses a tree-based change detection system. The default strategy (CheckAlways) verifies all components when any change occurs. The OnPush strategy only checks when: – Input references change – Event handlers trigger changes – Explicit detection is requested
Lazy Loading Architecture:
App Module ├── Core Module (Eager) ├── Shared Module (Eager) └── Route Configuration ├── /dashboard (Lazy) ├── /reports (Lazy) └── /admin (Lazy)
Prerequisites and Environment Setup
Installation Guide
- Install Angular CLI globally:
npm install -g @angular/cli
- Create new application (Skip if modifying existing):
ng new perf-app –strict –routing –style=scss && cd perf-app
Verify Environment
ng version
Expected output:
Angular CLI: 15.2.4
Node: 16.14.2
Package Manager: npm 8.5.0
Step-by-Step Implementation
1. Lazy Loading Setup
Basic Implementation (products.module.ts):
// app-routing.module.ts
const routes: Routes = [
{
path: ‘products’,
loadChildren: () => import(‘./products/products.module’)
.then(m => m.ProductsModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
Advanced Preloading Strategy:
// custom-preloading.service.ts
@Injectable({ providedIn: ‘root’ })
export class SelectivePreloadingService implements PreloadingStrategy {
preload(route: Route, load: () => Observable
2. Change Detection Optimization
OnPush Strategy Implementation:
// products-list.component.ts
@Component({
selector: ‘app-products-list’,
templateUrl: ‘./products-list.component.html’,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProductsListComponent {
@Input() products: Product[];
constructor(private cdr: ChangeDetectorRef) {}
refreshData() {
// Optional manual trigger
this.cdr.detectChanges();
}
}
Immutable Data Pattern:
updateProduct(updatedProduct: Product) {
this.products = this.products.map(p =>
p.id === updatedProduct.id ? { …p, …updatedProduct } : p
);
}
Practical Examples and Use Cases
E-commerce Scenario
Lazy Loading Structure:
const routes: Routes = [
{
path: ‘checkout’,
loadChildren: () => import(‘./checkout/checkout.module’)
.then(m => m.CheckoutModule),
data: { preload: true } // High-priority route
},
{
path: ‘product/:id’,
loadChildren: () => import(‘./product-details/product-details.module’)
.then(m => m.ProductDetailsModule)
}
];
Dashboard Widget (OnPush Example):
@Component({
selector: ‘sales-widget’,
template: `
Advanced Techniques and Optimization
Bundle Analysis and Optimization
- Install analyzer:
npm install webpack-bundle-analyzer –save-dev
- Generate build stats:
ng build –stats-json
- Analyze bundles:
npx webpack-bundle-analyzer dist/perf-app/stats.json
Common Optimizations:
- Disable Ivy for legacy projects
- Implement module federation
- Configure differential loading
Testing, Debugging, and Troubleshooting
Common Errors and Fixes
Lazy Loading Issue:
Error: Cannot find module ‘./products/products.module’
Solution:
// Ensure correct relative path:
loadChildren: () => import(‘./features/products/products.module’)
Change Detection Problem:
Component not updating with OnPush
Verification Steps:
1. Check input reference changes
2. Verify manual change detection calls
3. Ensure async pipe is properly used
Debugging Tools
- Angular DevTools: Component inspection
- Chrome Performance Tab: Profile change detection cycles
- Router Tracing:
RouterModule.forRoot(routes, { enableTracing: true })
Conclusion and Next Steps
Implementing lazy loading and optimized change detection can dramatically improve Angular application performance: - Reduce initial bundle size by 30-60% - Lower memory consumption - Improve runtime efficiency
Recommended Next Steps: 1. Implement Angular Universal (SSR) 2. Explore Zone.js optimization 3. Investigate Component Store patterns
Learning Resources: - Angular Performance Checklist - RxJS Optimization Techniques
> Key Insight: The most effective performance gains often come from architecture decisions made early in development. Strategically combine lazy loading with OnPush change detection for maximum impact.