Overview

  • How to use Angular lazy loading to split features to modules and load them only when needed.

  • The lazy-loaded SchedulerModule displays the Angular Scheduler component.

  • The initial bundle size is reduced to the necessary minimum.

  • See also other tips for improving the load time.

  • The Angular project includes a trial version of DayPilot Pro for JavaScript (see License below).

License

Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.

Angular Application Size and Loading Time

angular scheduler single bundle build

By default, Angular will produce one bundle that includes all dependencies and it will load it during the application startup. That means your users will have to wait until everything is loaded. It will work fine for small applications but for larger projects it will be necessary to apply a code splitting strategy that will reduce the initial loading time.

The bundle size can grow quickly, especially if you use third party libraries like DayPilot. DayPilot itself adds about 870 KB to the JavaScript bundle.

Depending on your Angular version, you may also see a warning or error like this:

Error: initial exceeded maximum budget. Budget 1.00 MB was not met by 94.98 kB with a total of 1.09 MB.

The main purpose of the error message is to warn you about the initial bundle size. On desktop machines running intranet applications, even a few megabytes won’t be a problem. However, on mobile devices with slow connection the loading time may become noticeable. In order to minimize the startup time, it’s a good idea to review optimization options and apply them if they are easily accessible.

How to Enable Route-Based Lazy Loading in Angular

Angular provides a solution - it lets you split the code into several modules that will be loaded when needed. That will let you keep the initial bundle size small and load the additional modules (with their dependencies) only when necessary. The following steps explain how to enable code splitting using Angular lazy-loaded modules.

1. How to Enable Routing in Your Angular Application

When creating your Angular application, use the —routing parameter to enable routing.

ng new angular-scheduler-lazy-loading --routing

The generated application will include an app-routing.module.ts file that looks like this:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

If you want to add routing to your existing Angular application, you can also create this file manually. Don’t forget to add AppRoutingModule to the imports section of your main AppModule in that case.

2. How to Add Lazy-Loaded Modules

In this step, we will add a new module with the Angular Scheduler. This SchedulerModule will handle the /scheduler route and display the Angular Scheduler component. The module will be lazy-loaded when this route is activated in the browser.

You can use Angular CLI to generate the module and add it to the routes:

ng generate module scheduler --route scheduler --module app.module

The updated app-routing.module.ts looks like this:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [{ path: 'scheduler', loadChildren: () => import('./scheduler/scheduler.module').then(m => m.SchedulerModule) }];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

The module (scheduler/scheduler-routing.module.ts) includes its own child routing logic that will instruct Angular which component to display:

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SchedulerComponent } from './scheduler.component';

const routes: Routes = [{ path: '', component: SchedulerComponent }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class SchedulerRoutingModule { }

Make sure that the DayPilotModule is only imported in SchedulerModule (and not in the AppModule). Otherwise, Angular would include it in the main bundle.

scheduler/scheduler.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { SchedulerRoutingModule } from './scheduler-routing.module';
import { SchedulerComponent } from './scheduler.component';
import {DayPilotModule} from "daypilot-pro-angular";
import {DataService} from "./data.service";
import {HttpClientModule} from "@angular/common/http";

@NgModule({
  declarations: [
    SchedulerComponent,
  ],
  imports: [
    CommonModule,
    SchedulerRoutingModule,
    DayPilotModule,
    HttpClientModule
  ],
  providers:    [ DataService ]
})
export class SchedulerModule { }

3. How to Pre-Load the Lazy Modules

To improve the loading time of the Scheduler module (which is now delayed until the user navigates to /scheduler) we can preload the modules right after the application startup.

To enable module pre-loading, use the preloadingStrategy config option of RouterModule.forRoot() method. If you specify PreloadAllModules as the strategy the application will only load the bundles required for the initial startup before the application is loaded but it will also immediately start pre-loading the lazy modules. That will not affect the initial loading time but it will improve the loading time for the dynamic routes.

import {NgModule} from '@angular/core';
import {PreloadAllModules, RouterModule, Routes} from '@angular/router';

const routes: Routes = [{
  path: 'scheduler', loadChildren: () => import('./scheduler/scheduler.module').then(m => m.SchedulerModule)
}];

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

4. How Does the Lazy Loading Affect the Output Bundles

When you switch to lazy loading of the Scheduler module you will see that the ng build command creates a separate chunk for the SchedulerModule (with all dependencies):

angular scheduler lazy chunk files build

The size of the initial bundle is reduced to 254 kB which make the initial load of the Angular application much faster.

Further Performance Improvements

Enable HTTP Compression

angular scheduler lazy loading http compression

The JavaScript files produced by Angular are text files that will benefit from HTTP compression. The HTTP compression can reduce the size of the data sent over the network by 70%.

Make sure that HTTP compression is enabled in your web server for JavaScript files. Most modern web servers will enable it automatically. You can see whether the compression is applied by checking the content-encoding response header (use the browser developer , Network tab).

Use a Content Delivery Network (CDN)

Using a CDN can reduce the time to 10% of the original download time (tens of milliseconds instead of hundreds of milliseconds). The CDN will serve the files from the location nearest to the client computer.

After configuring the CDN to mirror your site, you can tell Angular to load the JavaScript files from there using —deploy-url parameter. This will let you serve the main application file (index.html) from your server and use the CDN for dependencies (JavaScript, CSS).

ng build --deploy-url=https://cdn.yourwebsite.com/