Lesson 17 of 30
Ship the admin dashboard's code only to people who visit the admin dashboard — one dynamic import per route, no NgModule required.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Every component you import at the top of your route config gets bundled into the JavaScript the browser downloads on first load — whether the user ever visits that route or not. A settings page, an admin dashboard, a rarely-used export wizard: all of it ships up front unless you tell the router otherwise.
Lazy loading is telling the router: "don't fetch this component's code until someone actually navigates to this route." The bundler splits that component (and everything it imports) into its own chunk, and the browser fetches it on demand.
Instead of pointing a route at a component: you've already imported, you point it at a function that returns a dynamic import():
// app.routes.ts
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
export const routes: Routes = [
{ path: '', component: HomeComponent }, // in the main bundle — loads immediately
{
path: 'admin',
loadComponent: () =>
import('./admin/admin-dashboard.component').then((m) => m.AdminDashboardComponent),
},
];
HomeComponent is imported normally at the top of the file, so it's part of the initial bundle — that's correct, most visitors land on the home route. AdminDashboardComponent is never imported directly anywhere; loadComponent only imports it inside the function, which only runs when the router actually navigates to /admin. The bundler sees that dynamic import() and automatically splits admin-dashboard.component.ts — and its own dependencies — into a separate chunk that isn't part of the app's first-load JavaScript at all.
You can group several related lazy routes under one parent without pulling in an NgModule either — loadChildren now points at a plain array of Routes, not a module:
{
path: 'settings',
loadChildren: () => import('./settings/settings.routes').then((m) => m.SETTINGS_ROUTES),
},
// settings/settings.routes.ts
import { Routes } from '@angular/router';
export const SETTINGS_ROUTES: Routes = [
{ path: '', loadComponent: () => import('./settings-home.component').then((m) => m.SettingsHomeComponent) },
{ path: 'billing', loadComponent: () => import('./billing.component').then((m) => m.BillingComponent) },
];
AdminDashboardComponent directly — even just for a type reference — the bundler pulls it back into the main chunk, and loadComponent stops mattering. Route data types can go in a shared file both sides import without pulling in the component itself./admin waits on a chunk fetch that a non-lazy route wouldn't. That's usually the right trade for a rarely-visited route, and usually the wrong trade for something on your app's main path.loadChildren isn't the NgModule pattern anymore. If you're reading older Angular material, loadChildren used to only accept a module with forChild(). Point it at a Routes array like above — the router handles nesting without any module wrapper.React.lazyThis is the same technique as React.lazy(() => import(...)) paired with route-based code splitting in a React Router setup — a dynamic import() is a standard JavaScript feature the bundler hooks into, not an Angular-specific trick. The router-config version here builds directly on the routes-array mental model from the routing fundamentals lesson — loadComponent is just a different way of filling in what a route resolves to.