How can I improve load performance of Angular2 apps?

AngularM picture AngularM · Nov 30, 2016 · Viewed 43.9k times · Source

Angular2 app is loading slow, how can I improve the performance on load?

I use Angular2, typescript with html5.

currently my app takes 4 seconds to load. I host with Firebase and use cloudflare.

Things I'm doing / info:

  • I've compressed images.
  • I minify css
  • I minify js.
  • I use async on my scripts.
  • My scripts are in my .
  • The scripts are around 700kb
  • I used google speed test and get 65%
  • I used minified version of the libs I use e.g. bootstrap etc.
  • Using systemjs.
  • This is the seed app im using: https://github.com/mgechev/angular-seed

Flow:

When the app loads it shows a blue screen (this is the bootstrap css) and then 4 seconds later the app loads and works really fast. But takes 4 seconds to load. It seems the app.js file that systemjs minifies to is slowing the whole app, and not showing the views fast enough.

This is my website speed test: https://www.webpagetest.org/result/161206_F5_N87/

This is my website:

https://thepoolcover.co.uk/

Let me know if you need more information about my app and any other things I can do.

Answer

Vikash Dahiya picture Vikash Dahiya · Dec 6, 2016

A single page application generally takes more time while loading as it loads all necessary things at once.

I had also faced same problem and my team has optimized our project from loading in 8 seconds to 2 seconds by using following methods.

  1. Lazy loading a module : Lazy loading modules helps to decrease the startup time. With lazy loading our application does not need to load everything at once, it only needs to load what the user expects to see when the app first loads. Modules that are lazily loaded will only be loaded when the user navigates to their routes. Angular2 has introduced modules in its final release RC5. See below for step-by-step guide.

  2. Aot Compilation : With AoT, the browser downloads a pre-compiled version of the application. The browser loads executable code so it can render the application immediately, without waiting to compile the app first.

    It reduces the payload size : There's no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload. For more info see this.

  3. Webpack : Webpack is a popular module bundler, a tool for bundling application source code in convenient chunks and for loading that code from a server into a browser. You can configure your Angular 2 web application with webpack (see this guide).

  4. Remove scripts,stylesheet from index.html : Remove all scripts and stylesheet which are not needed in index.html. You can load these script dynamically in component itself by calling a service.

    Make a file script.service.ts which can load any script on demand for that component

\script.service.ts

import { Injectable } from '@angular/core';
declare var document: any;

@Injectable()
export class Script {

  loadScript(path: string) {
    //load script
    return new Promise((resolve, reject) => {
      let script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = path;
      if (script.readyState) {  //IE
        script.onreadystatechange = () => {
          if (script.readyState === "loaded" || script.readyState === "complete") {
            script.onreadystatechange = null;
            resolve({ loaded: true, status: 'Loaded' });
          }
        };
      } else {  //Others
          script.onload = () => {
            resolve({ loaded: true, status: 'Loaded' });
          };
      };
      script.onerror = (error: any) => resolve({ loaded: false, status: 'Loaded' });
      document.getElementsByTagName('head')[0].appendChild(script);
    });
  }
}

This is just a sample code to load script dynamically, you can customize and optimize it by yourself according to your need. For stylesheet you should load it in component using styleUrl.

  1. Use Browser Caching : Your webpage files will get stored in the browser cache when you use browser caching. Your pages will load much faster for repeat visitors and so will other pages that share those same resources. For more info https://varvy.com/pagespeed/leverage-browser-caching.html

  2. minimize the code in app.component.ts : minimize the code present in app.component.ts which always run when the app loads or reloads.

  3. set data on app Initialization : if you are using same api calls multiple times in your project or in components, or you are dependent upon same data in multiple component, instead of calling api multiple times what you can do is save the data as an object in service on app initialization. That service will act as a singleton throughout the project and you can access that data without calling api.


Lazy loading of modules step by step

  1. Modular structure : We have to divide our App into separate modules. For example an app may have a user side and an admin side and each will have its own different components and routes, so we will separate this two sides into modules admin.module.ts and user.module.ts.

  2. Root Module : Every Angular app has a root module class. By convention it's a class called AppModule in a file named app.module.ts , this module will import the above two module and also the AppComponent for bootstrap. You can also declare multiple components according to your need. Sample code in app.module.ts:

\app.module.ts

import { NgModule } from '@angular/core';
import { UserModule } from './user/user.module';
import { AdminModule } from './admin/admin.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login.component';

@NgModule({
  imports: [UserModule, AdminModule],
  declarations: [AppComponent, LoginComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }
  1. Routes : Now in your routes you can specify like the following

\app.router.ts

import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './login.component';

const routes: Routes = [
  { path: 'login', component: 'LoginComponent' }, //eager loaded
  { path: 'admin', loadChildren: './admin/admin.module#AdminModule' }, // Lazy loaded module
  { path: 'user', loadChildren: './user/user.module#UserModule' }  //lazy loaded module
];

Now when the application loads, it will only load LoginComponent and AppComponent code. These modules will only be loaded when we visit /admin or /user routes. Hence it will decrease the size of payload for loading into the browser, thus resulting in fast loading.

  1. Nesting Modules : Just like app.module every module has its own set of components and routes. As your project becomes larger, the nesting of modules inside module is the best way to optimize because we can lazily load those modules whenever we require.

PLEASE NOTE

Above code is only for explanation, please refer for full example https://angular-2-training-book.rangle.io/handout/modules/lazy-loading-module.html