Skip to main content
Lazy loading is a design pattern that delays loading of features until they’re actually needed. ScreenPulse uses Angular’s built-in lazy loading to dramatically improve initial load times and overall performance.

How Lazy Loading Works

Instead of bundling the entire application into a single JavaScript file, Angular’s build process creates separate bundles for each lazy-loaded module:
src/app/app-routing.module.ts
const routes: Routes = [
  { 
    path: '', 
    loadChildren: () => import('./pages/search/search.module')
      .then(m => m.SearchModule) 
  },
  { 
    path: 'favorites',
    canActivate: [AuthGuard],
    loadChildren: () => import('./pages/favorites/favorites.module')
      .then(m => m.FavoritesModule) 
  },
  { 
    path: 'auth',
    loadChildren: () => import('./pages/auth/auth.module')
      .then(m => m.AuthModule) 
  }
];
The import() syntax is a JavaScript dynamic import that returns a Promise. Angular uses this to load modules asynchronously when the route is activated.

Loading Flow

1

Initial page load

Browser downloads:
  • main.js (AppModule, CoreModule, LayoutModule)
  • polyfills.js (browser compatibility)
  • runtime.js (webpack module loader)
  • styles.css (global styles)
2

User navigates to /favorites

Browser downloads:
  • favorites-module.js (FavoritesModule + components)
  • Any dependencies not already loaded
3

Module instantiation

Angular:
  • Instantiates the FavoritesModule
  • Creates component instances
  • Renders the favorites page
4

Subsequent navigation

Module is cached - no additional download needed

Build Output Example

When you build ScreenPulse, you’ll see separate chunk files:
npm run build
dist/screenpulse/
├── main.[hash].js              # AppModule, CoreModule, LayoutModule (~200 KB)
├── polyfills.[hash].js         # Browser compatibility (~40 KB)
├── runtime.[hash].js           # Module loader (~2 KB)
├── search-module.[hash].js     # SearchModule (lazy-loaded, ~80 KB)
├── favorites-module.[hash].js  # FavoritesModule (lazy-loaded, ~60 KB)
├── auth-module.[hash].js       # AuthModule (lazy-loaded, ~50 KB)
└── styles.[hash].css           # Global styles
Actual file sizes will vary based on your dependencies and build configuration. Use ng build --stats-json and webpack-bundle-analyzer to visualize bundle sizes.

Performance Benefits

Without Lazy Loading

Initial Bundle: 400 KB
Load Time: 2.5s on 3G
Time to Interactive: 3.0s

With Lazy Loading

Initial Bundle: 250 KB  (37% reduction)
Load Time: 1.5s on 3G   (40% faster)
Time to Interactive: 1.8s (40% faster)

Faster Initial Load

Users only download the code for the landing page, not the entire app

Reduced Bundle Size

Main bundle is 40-60% smaller with proper lazy loading

Better Caching

Browsers cache feature bundles independently - updates to one feature don’t invalidate all caches

Improved User Experience

Faster time-to-interactive means users can start using the app sooner

Code Splitting Strategy

ScreenPulse splits code at the feature level:

What Goes in the Initial Bundle

  • Root component (AppComponent)
  • Router configuration
  • Global providers (interceptors)
  • Authentication services (though these use providedIn: 'root')
  • Guards and interceptors (registered in AppModule)
  • Navbar component
  • Footer component
  • Application shell that’s visible on every page
  • Angular core packages
  • RxJS
  • Angular Material core

What’s Lazy Loaded

  • SearchModule: Search page, search bar, carousel, results table
  • FavoritesModule: Favorites page, favorites cards, sorting controls
  • AuthModule: Login/register pages, auth forms
  • Feature-specific Material modules: Only load Material components when needed

Preloading Strategies

Angular can preload lazy modules in the background after the initial render:
src/app/app-routing.module.ts
import { PreloadAllModules } from '@angular/router';

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      preloadingStrategy: PreloadAllModules  // Preload all lazy modules
    })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Preloading Options

Load modules only when user navigates to the route
preloadingStrategy: NoPreloading
Best for: Apps with many large features that most users won’t visit

Optimizing Lazy Loading

1

Keep the initial bundle small

Only include essential services and components in CoreModule and LayoutModule
2

Split features appropriately

Each major feature should be its own lazy-loaded module
3

Avoid importing feature modules directly

Never import a lazy-loaded module in AppModule - only use loadChildren
4

Use SharedModule wisely

Put truly shared components in SharedModule, but don’t bloat it with feature-specific code
5

Analyze bundle sizes

Use ng build --stats-json and webpack-bundle-analyzer to identify optimization opportunities

Common Pitfalls

Accidental Eager LoadingIf you import a lazy-loaded module anywhere else in the app, it becomes eagerly loaded:
// DON'T DO THIS
import { FavoritesModule } from './pages/favorites/favorites.module';

@NgModule({
  imports: [FavoritesModule]  // This defeats lazy loading!
})
Instead, only use loadChildren in routing configuration.
Shared Services in Feature ModulesProviding a service in a lazy-loaded module creates a new instance for that module:
// DON'T DO THIS for singleton services
@NgModule({
  providers: [AuthService]  // Creates a new instance!
})
export class FavoritesModule { }
Instead, use providedIn: 'root' for singleton services:
@Injectable({ providedIn: 'root' })
export class AuthService { }

Testing Lazy Loading

Verify lazy loading in Chrome DevTools:
1

Open DevTools

Press F12 and go to the Network tab
2

Filter by JS files

Click the “JS” filter to show only JavaScript files
3

Load the application

Refresh the page and observe files being downloaded
4

Navigate to a lazy route

Click a link to /favorites and watch for the new bundle download
You should see files like favorites-module.[hash].js downloaded only when navigating to /favorites.

Next Steps

Routing

Learn about route configuration and guards

Module Structure

Understand how modules are organized

Build Configuration

Optimize production builds

Performance

Additional performance optimization techniques

Build docs developers (and LLMs) love