Optimized Angular apps:

  • smaller

  • faster

  • better

Web App Performance

Network bandwidth

Device performance

}

}

Generate smaller bundles

Optimize the code to display UI updates faster

Network performance strategy

  • Make overall bundle size smaller

  • Split bundle and download only what we need for the starting-up

  • Cache network responses for the future usage

Build the app using prod

$ ng build --prod
  • Using Ahead of Time compilation

  • Using Build Optimizer

  • Registering Angular Service Worker (if enabled)

  • Executes enableProdMode() via setting prod environment

Recipe #1

How to

$ ng build --prod --source-map
$ npx source-map-explorer main.bundle.js

Use lazy loading

  • Download the only code needed to start the app

  • Use CanLoad guard to mediate navigation

  • Preload all the modules (except the ones protected by CanLoad) by using PreloadAllModules strategy

  • 100% flexibility with your custom PreloadingStrategy

Recipe #2

How to

const appRoutes: Routes = [{
  path: 'tweets',
  loadChildren: 'tweets/tweets.module#TweetsModule'
}]
const tweetsRoutes: Routes = [{
  path: '',
  component: TweetFeedsComponent
}];

app-routing.module.ts

tweets/tweets-routing.module.ts

Preloading strategy

@NgModule({
  imports: [RouterModule.forRoot(appRoutes, {
    preloadingStrategy: PreloadAllModules
  })],
  exports: [RouterModule]
})

app-routing.module.ts

Consider server-side rendering

  • Better first-load experience

  • Social links with previews of a web site

  • Better for SEO

Recipe #4

Bootstrap

Load HTML

First meaningful paint

Bootstrap

Load HTML

First meaningful paint

No SSR

SSR

<app-root>Loading</app-root>

Loading

How to

A short way

A long way

$ ng add @ng-toolkit/universal
$ npm run build:prod
$ npm run server
$ ng generate universal --client-project=ssr

...and follow the guide at https://angular.io/guide/universal

Angular change detection (CD)

Data bindings

Update DOM

Event handlers

}

Change detection

}

UI render

Trigger

Ready

}

60FPS / 17ms

Code performance strategy

  • Make each change detection faster

  • Reduce number of change detections

  • Render as few as possible DOM changes

Use pure pipes instead of methods

<span>{{ relativeDate(tweet.createdAt) }}</span>

Calculated on every change detection

Recipe #5

<span>{{ tweet.createdAt | relativeDate }}</span>

Calculated only if the value was changed

Use OnPush CD strategy

Recipe #6

  • Every time

  • Any event happens

  • All components

}

By default

Use OnPush CD strategy

Recipe #6

  • Every time

  • Any event happens

  • All components

}

By default

Use OnPush CD strategy

Recipe #6

  • Every time

  • Any event happens

  • All components

}

By default

Use OnPush CD strategy

Recipe #6

  • Every time

  • Any event happens

  • All components

}

By default

How to

import { ..., ChangeDetectionStrategy } from '@angular/core';

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush
})
  • The @Input reference changes

  • An event occurres from the component or one of its children

  • Running change detection explicitly

  • Observable linked to the template via the async pipe emits a new value

ChangeDetectionStrategy.OnPush

Go for your own CD schedule

  • Disabling CD for the component completely

  • Running some code outside Angular CD

Recipe #7

How to

import { ..., ChangeDetectorRef } from '@angular/core';

class RealTimeList {
  constructor(private ref: ChangeDetectorRef) {
    ref.detach();
    setInterval(() => {
      this.ref.detectChanges();
    }, 1000);
  }
}
  • detach() / reattach()

  • detectChanges() / tick() / markForCheck()

How to

import { ..., NgZone } from '@angular/core';

class MyComponent implements OnChanges {

  constructor(private _ngZone: NgZone ) {}

  log() {
    this._ngZone.runOutsideAngular(() => {
      // Any code will not cause CD
    }}));
  }
}

Use trackBy in ngFor loops

  • DOM manipulations are expensive

  • Immutable practices generate a new DOM collection

Recipe #8

How to

export class TweetListComponent implements OnInit {
  ...

  trackById(index, tweet) {
      return tweet.id;
  }
}
<div *ngFor="let tweet of tweets; trackBy: trackById">

Angular App Performance

Networking

Code execution

}

}

  • Production mode

  • Lazy loading

  • Service worker

  • Server-side rendering

  • Using pure pipes

  • OnPush CD strategy

  • Custom CD strategy

  • Using trackBy

Thank you!

Questions?

Made with Slides.com