angularangular-materiallazy-loadingbundle

Lazying loading Angular Material Modules and bundle optimization


I'm building the Angular application with version 17 and after bundling, the size exceeds the budget. With the source map explorer, the illustration shows there are multiple Angular Material modules aren't lazy-loaded such as form-field, CDK, and list. From the standalone implementation guidance, I've configure the lazy routes and the lazy components, but these Material modules are still in the initial bundles.

Since I'm using Nx, the build script is:

"build-ng-frontend": "nx build ng-frontend --configuration production --optimization --base-href ./",

Here is the script for source map generation:

"bundle-ng-frontend-report": "nx build ng-frontend --configuration production --source-map && source-map-explorer dist/apps/ng-frontend/browser/*.js",

Here is an example,

// app routes
export const APP_ROUTES: Route[] = [
  {
    path: 'topics',
    loadChildren: () =>
      import('./modules/help-center/routes').then((m) => m.HELP_CENTER_ROUTES),
  },
  {
    path: 'projects/:projectSlug',
    loadChildren: () =>
      import('./modules/project/routes').then((m) => m.PROJECT_ROUTES),
  },
  {
    path: '',
    loadChildren: () =>
      import('./modules/entry/routes').then((m) => m.ENTRY_ROUTES),
  },
];

// help center routes
export const HELP_CENTER_ROUTES: Routes = [
  {
    path: '',
    loadComponent: () =>
      import('./views/help-center-view.component').then(
        (m) => m.HelpCenterViewComponent
      ),
    children: [
      {
        path: ':name',
        loadComponent: () =>
          import('./components/main-content/main-content.component').then(
            (m) => m.MainContentComponent
          ),
      },
    ],
  },
];

Is it inevitable to have larger initial bundle size, or I misunderstand something in the build? Here is my repo if you need further investigation.

source map explorer


Solution

  • I guess the dependencies come from the toolbar. In the app component there are no Inputs filled in though so I'm not sure if the business logic rich toolbar should be used in the app component.

    If yes, then I would consider using @defer with when condition to defer loading of the conditional data that are present in the toolbar.

    @defer (when this.snav && this.settings && this.projects)
     // the if condition needs to be present only if
     // the `when` condition could became falsy again.
     @if (this.snav && this.settings && this.projects) {
            <mat-form-field
              appearance="outline"
              style="margin-left: 1rem; margin-top: 20px"
            >
    

    Using @defer could also be considered even in the app-component:

    @defer(on immediate) {
      <app-toolbar></app-toolbar>
    } @loading {
      <div style="height: 60px (match toolbar hegiht)"></div>
    }
    

    That will load the toolbar when the application first renders. I suggest adding a transparent/colored div of the height of the toolbar as a loading placeholder that prevents content "jump".