By default the browser downloads the whole app before the first page appears. Lazy loading splits the app into pieces and downloads a page only when someone visits it. Smaller first downloads mean faster pages.
What you will learn
- How to lazy load a route with
loadComponent - How to lazy load a group of routes with
loadChildren - How to read the build output and how
@deferworks
Lazy load a single page
Change the routes so heavy pages are imported when needed. Notice that the page imports are removed from the top of the file.
// src/app/app.routes.ts
import { Routes } from '@angular/router';
import { Home } from './pages/home';
import { NotFound } from './pages/not-found';
import { authGuard } from './auth-guard';
export const routes: Routes = [
{ path: '', component: Home, title: 'Home' },
{
path: 'about',
loadComponent: () => import('./pages/about').then((m) => m.About),
title: 'About',
},
{
path: 'products',
loadChildren: () => import('./products/product.routes').then((m) => m.PRODUCT_ROUTES),
},
{
path: 'login',
loadComponent: () => import('./auth/login').then((m) => m.Login),
title: 'Login',
},
{
path: 'dashboard',
loadComponent: () => import('./auth/dashboard').then((m) => m.Dashboard),
canActivate: [authGuard],
title: 'Dashboard',
},
{ path: '**', component: NotFound, title: 'Not found' },
];
Lazy load a group of routes
// src/app/products/product.routes.ts
import { Routes } from '@angular/router';
import { ProductList } from './product-list';
import { ProductDetail } from './product-detail';
export const PRODUCT_ROUTES: Routes = [
{ path: '', component: ProductList, title: 'Products' },
{ path: ':id', component: ProductDetail, title: 'Product details' },
];
The products path is now a prefix. /products matches the empty child path, and /products/3 matches :id. The product pages are downloaded only when someone opens /products.
See it in the build
Run the production build:
ng build
The output now lists several lazy chunk files next to the initial bundle, with names based on the pages, such as chunk-XXXX.js. The initial total is smaller than before because the lazy pages are not included.
Defer parts of a page
Inside a template, @defer loads a section later, for example when it scrolls into view:
@defer (on viewport) {
<app-reviews />
} @placeholder {
<p>Reviews will load when you scroll here.</p>
} @loading {
<p>Loading reviews...</p>
}
The components used inside @defer are moved to their own chunk. Use it for heavy parts below the fold, not for content that matters for search or the first view.
The key parts
loadComponentandloadChildrenuse the dynamicimport()of JavaScript, which the build tool turns into a separate file.- Keep the first page (Home) eager. A lazy first page just adds a delay.
- Do not import a lazy component in another file's
importsor route, or it goes back into the main bundle. @defertriggers includeon viewport,on idle,on interactionandon timer(...).
Try it yourself
- Run
ng buildbefore and after this lesson and compare the initial total size. - Open the browser DevTools Network tab and watch a chunk download when you click About.
- Lazy load the Contact page you created earlier.
Quick check
- What is the difference between
loadComponentandloadChildren? - Why should the home page usually not be lazy loaded?
- What does
@defer (on viewport)do?
You can now move between pages. Next, get data from a server with HttpClient. Read more in the lazy loading guide.