Routing
Lazy Loading
Master Angular Lazy Loading, covering route-level code splitting, loadComponent, loadChildren, preloading strategies, and bundle optimization.
1. Learning Objectives
In this lesson, you will master lazy loading in Angular. By the end of this topic, you will be able to:
- Explain how lazy loading improves initial page load performance.
- Use
loadComponentto lazy-load standalone components at the route level. - Use
loadChildrento lazy-load entire route configuration modules. - Configure preloading strategies to preload lazy-loaded routes in the background.
- Verify code splitting by inspecting bundled output chunks.
2. Overview
By default, Angular bundles all components into a single JavaScript file. As the application grows, this file becomes large, slowing down the initial page load. Lazy loading solves this by splitting the application into separate chunks that are downloaded on-demand when the user navigates to the corresponding route.
3. Why This Topic Matters
Lazy loading is critical for production Angular applications:
- Initial Load Performance: A large enterprise application with dozens of feature modules can produce a multi-megabyte JavaScript bundle. Lazy loading ensures users only download the code they need for the current page, dramatically reducing the Time to Interactive (TTI) metric.
- Accidental Eager Import: A common mistake is importing a lazy-loaded component directly in a parent module or route file using a standard
importstatement. This causes the bundler to include the component in the main bundle, defeating the purpose of lazy loading entirely.
4. Real-World Analogy
Think of lazy loading like **a streaming video platform**:
- Eager Loading (Downloading entire movie library): Without lazy loading, every movie is downloaded to your device upfront before you can watch anything. This takes a very long time and wastes bandwidth.
- Lazy Loading (Streaming on-demand): Only the movie you select is streamed. Other movies are downloaded only when you choose to watch them.
- Preloading (Smart buffering): After the current movie starts playing, the platform quietly pre-buffers the next episode in the background, so it loads instantly when you click "Next Episode".
5. Core Concepts
Angular provides two primary lazy loading mechanisms:
- loadComponent: Lazy-loads a single standalone component using a dynamic
import()expression. Best for individual routes mapping to standalone components. - loadChildren: Lazy-loads a child routes configuration (either from a standalone routes file or a legacy NgModule). Best for feature areas with multiple nested routes.
- Preloading Strategies: After the main bundle loads, Angular can preload lazy-loaded chunks in the background. The built-in
PreloadAllModulesstrategy downloads all lazy chunks after the initial render completes.
| Mechanism | Use Case | Syntax |
|---|---|---|
| loadComponent | Lazy-load a single standalone component. | loadComponent: () => import('./path').then(m => m.Comp) |
| loadChildren | Lazy-load an entire child routes configuration. | loadChildren: () => import('./path').then(m => m.routes) |
6. Syntax & API Reference
Below are route configurations demonstrating both loadComponent and loadChildren:
Enabling Preloading
7. Visual Diagram
This diagram displays the lazy loading lifecycle:
8. Live Example — Full Working Code
Below is a standalone component that is designed to be lazy-loaded:
To verify lazy loading is working correctly, run the production build command and inspect the output:
9. Interactive Playground
Try It Yourself Challenges:
- Convert an eagerly loaded route to use
loadComponentand verify the build output produces a separate chunk file. - Add a standard
importstatement for a lazy-loaded component in the parent route file and observe how it defeats code splitting.
10. Common Mistakes
| Mistake | Why it happens | Wrong | Correct |
|---|---|---|---|
| Eagerly importing a lazy-loaded component | Adding a standard top-level import { SettingsComponent } from '...' statement in the routes file. The bundler includes it in the main chunk, defeating lazy loading. |
import { Settings } from './settings'; { path: 'settings', component: Settings } |
{ path: 'settings', loadComponent: () => import('./settings').then(m => m.Settings) } |
| Using component instead of loadComponent | Specifying component on a route instead of loadComponent. This always eagerly loads the component. |
{ path: 'x', component: XComponent } |
{ path: 'x', loadComponent: () => import('...') } |
11. Best Practices
- Lazy-load feature areas: Group related functionality (like an admin panel or user settings area) into separate route files and use
loadChildrento load the entire group on demand. - Use PreloadAllModules for critical routes: Enable the
PreloadAllModulesstrategy to download lazy-loaded chunks in the background after the initial page renders, improving navigation speed for subsequent routes. - Avoid standard imports of lazy components: Never use a top-level
importstatement for components or route files that should be lazy-loaded. Only reference them inside the dynamicimport()expression.
12. Browser Compatibility/Requirements
Lazy loading uses dynamic import() expressions, which are supported in all modern browsers. The Angular CLI build process handles code splitting automatically during compilation.
13. Interview Questions
Q1: What is the difference between loadComponent and loadChildren in Angular routing?
Answer: loadComponent lazy-loads a single standalone component for one route. loadChildren lazy-loads an entire child routes configuration (an array of route definitions), which is ideal for feature areas with multiple nested routes that should all be split into a single chunk.
Q2: How do you verify that lazy loading is working correctly?
Answer: Run the production build (ng build) and inspect the output directory. Lazy-loaded routes should produce separate chunk files (e.g. chunk-XXXX.js). You can also open the browser Network tab and observe that separate JavaScript files are downloaded on-demand when navigating to lazy-loaded routes.
14. Debugging Exercise
The settings component is supposed to be lazy-loaded, but it always appears in the main bundle. Identify the bug:
Diagnosis: Line 1 contains a standard top-level import statement for SettingsComponent. Even though the route uses loadComponent with a dynamic import, the static import on Line 1 forces the bundler to include the component in the main chunk. The dynamic import becomes redundant.
Fix: Remove the static import statement on Line 1. Only reference the component inside the dynamic import() expression.
15. Practice Exercises
Exercise 1: Implement feature-level lazy loading
Create a "Reports" feature area with three child routes (Overview, Sales, Inventory). Use loadChildren to lazy-load the entire feature area. Enable PreloadAllModules and verify the chunk files are preloaded after initial render using the browser Network tab.
16. Scenario-Based Challenge
The Performance Optimization Challenge:
An Angular application has a main bundle size of 2.5 MB. The app contains feature areas for Products, Orders, Admin, and Analytics. Only the Home page is visited on the first load. Redesign the route configuration to lazy-load all feature areas and implement a custom preloading strategy that only preloads routes marked with data: { preload: true }.
17. Quick Quiz
Q1: Which route property should you use to lazy-load a single standalone component?
A) component
B) loadChildren
C) loadComponent
Answer: C — The loadComponent property uses a dynamic import to lazy-load a single standalone component.
18. Summary & Key Takeaways
- Lazy loading splits application code into separate chunks downloaded on-demand, improving initial load performance.
- Use
loadComponentfor single standalone components andloadChildrenfor multi-route feature areas. - Never use static top-level import statements for lazy-loaded components.
- Enable
PreloadAllModulesto preload lazy chunks in the background after initial render.
19. Cheat Sheet
| API | Purpose |
|---|---|
loadComponent |
Lazy-loads a single standalone component via dynamic import. |
loadChildren |
Lazy-loads a child routes configuration via dynamic import. |
withPreloading(PreloadAllModules) |
Preloads all lazy chunks in the background after initial render. |