Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Angular Performance Workshop at ReactiveConf in Bratislava, October 2017

Angular Performance Workshop at ReactiveConf in Bratislava, October 2017

Slides from my Talk at reactive conf in Bratislava.

15934fa2aa7b2ce21f091e9b7cffa856?s=128

Manfred Steyer
PRO

October 27, 2017
Tweet

Transcript

  1. Through the Sound Barrier High-Performance Applications with Angular Manfred Steyer

    SOFTWAREarchitekt.at
  2. About me… • Manfred Steyer • SOFTWAREarchitekt.at • Trainer &

    Consultant • Focus: Angular • Google Developer Expert (GDE) Page ▪ 3 Manfred Steyer
  3. Turbo Button

  4. Quick Wins Bundling Minification enableProdMode()

  5. Contents • Lazy Loading and Preloading • Performance for Data

    Binding with OnPush • AOT and Tree Shaking • Caching with Service Worker
  6. Lazy Loading

  7. Module Structure Page ▪ 9 AppModule … … … SharedModule

    Root Module Feature Modules Shared Module
  8. Lazy Loading Page ▪ 10 AppModule … … … SharedModule

    Root Module Feature Modules Shared Module
  9. Root Module with Lazy Loading Page ▪ 11 const APP_ROUTE_CONFIG:

    Routes = [ { path: 'home', component: HomeComponent }, { path: 'flights', loadChildren: './[…]flight-booking.module#FlightBookingModule' } ];
  10. Routes for "lazy" Module Page ▪ 12 const FLIGHT_ROUTES =

    [ { path: '', component: FlightBookingComponent, […] }, […] }
  11. Routes for "lazy" Module Page ▪ 13 const FLIGHT_ROUTES =

    [ { path: 'subroute', component: FlightBookingComponent, […] }, […] } flight-booking/subroute Triggers Lazy Loading w/ loadChildren
  12. DEMO

  13. Lazy Loading • Lazy Loading means: Loading it later •

    Better startup performance • Delay during execution for loading on demand
  14. Preloading

  15. Idea • Module that might be needed later are loaded

    after the application started • When module is needed it is available immediately Page ▪ 17
  16. Activate Preloading Page ▪ 18 … imports: [ […] RouterModule.forRoot(

    ROUTE_CONFIG, { preloadingStrategy: PreloadAllModules }); ] …
  17. Performance- Tuning with OnPush

  18. DEMO

  19. OnPush flights flight flight {{ flight.id }} {{ flight.id }}

    FlightSearch Card Card Angular just checks when “notified”
  20. "Notify" about change? • Change bound data (@Input) • OnPush:

    Angular just compares the object reference! • e. g. oldFlight === newFlight • Raise Event within the component • Notify a bound observable • Trigger it manually • Don't do this at home ;-) • At least: Try to avoid this
  21. Activate OnPush @Component({ […] changeDetection: ChangeDetectionStrategy.OnPush }) export class FlightCard

    { […] @Input() flight; }
  22. Change Inputs flights flight flight {{ flight.id }} {{ flight.id

    }} FlightSearch Card Card flightold === flightnew
  23. Observables and OnPush <flight-card [item]="flight$ | async" […]> </flight-card>

  24. DEMO

  25. Ahead of Time (AOT) Compilation

  26. Angular Compiler HTML Template JavaScript Template Compiler

  27. Approaches • JIT: Just in Time, at runtime • AOT:

    Ahead of Time, during build
  28. Advantages of AOT • Better Startup-Performance • Smaller Bundles: You

    don't need to include the compiler! • Tools can easier analyse the code • Remove not needed parts of frameworks • Tree Shaking
  29. Angular CLI • ng build --prod • @ngtools/webpack with AotPlugin

    • Soon AngularCompilerPlugin • Can be used without CLI too
  30. DEMO

  31. Tree Shaking

  32. Challenges • Most tree shaking tools are conservative • They

    just remove code when they are 100% sure • Very often, they aren't sure :-) • Solution: Angular Build Optimizer • Rewrites compiled code • Currently: Experimental
  33. Sample Application w/ Angular Material

  34. RxJS is huge

  35. RxJS • We don't need every operator/ method • But:

    Methods are not tree-shakable for CLI/ webpack and others • Solution: Just import methods you need • Imports are patching Observable
  36. Import Operators this.http.get<Flight>(url) .filter(f => f.price < 300) .map(f =>

    toFlightOffer(f)) .subscribe(…); import 'rxjs'; // Import all --> Bad!
  37. Import Operators import 'rxjs/add/operator/map'; // Patch Observable --> add map

    import 'rxjs/add/operator/filter'; this.http.get<Flight>(url) .filter(f => f.price < 300) .map(f => toFlightOffer(f)) .subscribe(…);
  38. Better Alternative: Lettable Operators this.http.get<Flight>(url) .pipe( filter(f => f.price <

    300), map(f => toFlightOffer(f)) ) .subscribe(…); import { map, filter } 'rxjs/operators';
  39. Removing Whitespaces

  40. Removing Whitespaces <p> Hello</p> <p>World! </p>

  41. Removing Whitespaces <p> Hello</p> <p>World! </p> \n //Pseudo Code createNode('p',

    ' Hello World'); createNode('TEXT-NODE', '\n'); createNode('p', 'World!'); Template Compiler
  42. Removing Whitespaces <p> Hello</p> <p>World! </p> \n //Pseudo Code createNode('p',

    ' Hello World'); createNode('TEXT-NODE', '\n'); createNode('p', 'World!'); Template Compiler
  43. Removing Whitespaces @Component({ selector: 'flight-card', templateUrl: './flight-card.component.html', styleUrls: ['./flight-card.component.css'], preserveWhitespaces:

    false }) export class FlightCardComponent { […] }
  44. Caching with Service Worker

  45. What are Service Workers? • Background Tasks • Web App

    installs them • Are activated and deactivated on demand
  46. Service Worker und Caching/ Offline • Intercept requests • Decide

    how to respond (Cache, Network) • Same Origin Policy • Caching Patterns • Cache only • Network only • Try cache first, then network • Try network first, then cache • etc.
  47. Angular 5: ServiceWorkerModule

  48. Service Worker with Workbox (sw.js) importScripts('./assets/workbox-sw.js'); const workboxSW = new

    WorkboxSW();
  49. Service Worker with Workbox (sw.js) importScripts('./assets/workbox-sw.js'); const workboxSW = new

    WorkboxSW(); const networkFirst = workboxSW.strategies.networkFirst(); const cacheFirst = workboxSW.strategies.cacheFirst();
  50. Service Worker with Workbox (sw.js) importScripts('./assets/workbox-sw.js'); const workboxSW = new

    WorkboxSW(); const networkFirst = workboxSW.strategies.networkFirst(); const cacheFirst = workboxSW.strategies.cacheFirst(); workboxSW.router.registerRoute( new RegExp('^http:\/\/www.angular.at\/api\/'), networkFirst); workboxSW.router.registerRoute(/./, cacheFirst);
  51. DEMO

  52. Server Side Rendering

  53. Why Server Side Rendering? Prerender 1st Page Start up performance

    Consumer
  54. renderModuleFactory […] renderModuleFactory(moduleFactory, { document: indexFileContentsAsString, url: options.req.url }) .then(string

    => { […] }); […] Available since Angular 4.0
  55. DEMO

  56. Challenges Other conditions Separate Services for Server and Client-Seite Renderer

    abstracts DOM 3rd parts libs Angular 5: Server Side DOM Simulation (partly)
  57. More about this in my Medium Account • Configuration Details,

    Samples etc. • https://medium.com/@ManfredSteyer/angular-performance-tuning- article-series-6e3c33707b25
  58. Conclusion Quick Wins Lazy Loading and Preloading OnPush w/ Immutables

    and Observables AOT and Tree Shaking Caching w/ Service Worker
  59. Contact and Downloads [mail] manfred.steyer@SOFTWAREarchitekt.at [blog] SOFTWAREarchitekt.at [twitter] ManfredSteyer