Write Angular like a pro. Angular Icon

Follow the ultimate Angular roadmap.

Lazy Load Standalone Components with "loadComponent"

Version 14.x of Angular introduces this fantastic concept of “standalone components” and changes the way we can optimize for performance via lazy-loading.

Standalone components no longer have an @NgModule, so how do we lazy load them via the router?

Using an NgModule makes it easy to code split on the router level, but with the introduction of standalone components things have changed ever so slightly (for the better).

With NgModule, we’d have something like this which would lazy load the MenuModule, which is fine:

export const AppRoutes: Routes = [
  {
    path: 'menu',
    loadChildren: () =>
      import('./menu/menu.module').then((x) => x.MenuModule),
  }
];

@NgModule({
  imports: [RouterModule.forRoot(AppRoutes)]
})
export class AppModule {}

We would then have something like this inside the MenuModule routes:

export const MenuRoutes: Routes = [
  {
    path: 'menu',
    component: MenuListComponent
  },
  {
    path: 'menu/:id',
    component: MenuSingleComponent
  }
];

@NgModule({
  imports: [RouterModule.forChild(MenuRoutes)]
})
export class MenuModule {}

No code splitting and lazy loading is happening at this point, only at the MenuModule level.

That means even if we never navigate to the MenuSingleComponent, it still gets loaded in the bundle.

Now imagine that on a larger scale, that’s a lot of unused code that’s slower to load across the network.

👑 There is a “Single Component Angular Module” pattern that was pioneered to allow us to lazy load individual components, because currently our MenuModule ships with both MenuListComponent and MenuSingleComponent.

So what can standalone components do, how do they help us?

First, let’s refactor our MenuRoutes to this:

export const MenuRoutes: Routes = [
  {
    path: 'menu',
    component: MenuListComponent
  },
  {
    path: 'menu/:id',
    component: MenuSingleComponent
  }
];

// ❌ Commented out, where we're going we don't need modules 🚀👨‍🚀
// @NgModule({
//   imports: [RouterModule.forChild(MenuRoutes)]
// })
// export class MenuModule {}

No NgModule.

With the router’s loadChildren property, we can now pass in the routes directly without using RouterModule.forChild:

export const AppRoutes: Routes = [
  {
    path: 'menu',
    loadChildren: () =>
      import('./menu/menu.routes').then((x) => x.MenuRoutes),
  }
];

💥 I’ve renamed the ./menu/menu.module file to ./menu/menu.routes, as it’s no longer a module and simply holds just an exported route constant.

So at this point things are mostly the same, so how can we further code split and lazy load the standalone components?

At present, we’re using the component property on the routes, what if we introduce a new property?…

Say hello to the new loadComponent property, which uses a dynamic import statement like an NgModule would, but for a standalone component:

export const MenuRoutes: Routes = [
  {
    path: 'menu',
    loadComponent: () =>
      import('./menu-list/menu-list.component').then((x) => x.MenuListComponent),
  },
  {
    path: 'menu/:id',
    loadComponent: () =>
      import('./menu-single/menu-single.component').then((x) => x.MenuSingleComponent),
  }
];

What’s also great about this approach is it uses the type system to find the x.MenuListComponent and x.MenuSingleComponent references.

That means we no longer need to static import { MenuListComponent } from '...' and import { MenuSingleComponent } from '...' at the top of our routes. Even cleaner.

We now end up with more automatic code splitting from doing this too.

Beforehand, we just had the entire MenuModule code split and lazy loaded.

Now, we have three different bundles that are lazy loaded - the MenuRoutes will be in its own verrrrry tiny bundle (literally just the routes array and import statements), followed by the MenuListComponent and MenuSingleComponent bundles which hold the further logic.

A win-win for performance and clean code.

And that’s it! Standalone components are super and offer some nice new patterns with Angular.

What’s more is they can be combined with existing NgModules in your applications to help you achieve anything you like.

🚀 Want to learn even more awesome Angular practices?
Check out my new Angular Courses if you’re serious about taking your skills to the top! There’s so much about Standalone Components and all the new best practices in the course.

Thanks for reading, happy lazy loading!

Learn Angular the right way.

The most complete guide to learning Angular ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover