Slide 1

Slide 1 text

` Mike Hartington • @mhartington Ionic, Angular GDE AWESOME PWAS WITH ANGULAR

Slide 2

Slide 2 text

LET'S START WITH AN EXPERIMENT

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

14 SECONDS AVERAGE LOAD
 TIME ON MOBILE

Slide 5

Slide 5 text

AVERAGE EXPERIENCE MBs of JS over the network Slow load times Lower user engagement

Slide 6

Slide 6 text

HOW DO PWAS 
 RELATE TO THIS?

Slide 7

Slide 7 text

PWAs provide an optimized experience 
 that is faster and more resilient

Slide 8

Slide 8 text

–Mike Hartington "Essentially, a responsive web site
 that's fast and works offline"

Slide 9

Slide 9 text

–Mike Hartington "Marketing Words"

Slide 10

Slide 10 text

PROGRESSIVE WEB APPS Fast Progressive Secure Integrated

Slide 11

Slide 11 text

Cool, so can I PWA with Angular?

Slide 12

Slide 12 text

Make it Fast Make it Cache Make it Last

Slide 13

Slide 13 text

MAKE IT FAST

Slide 14

Slide 14 text

Goal: Ship less code Lazy Loading best practices Choosing the right libraries

Slide 15

Slide 15 text

LAZY LOADING Lazy load as much as possible! Reduce initial load time

Slide 16

Slide 16 text

RouterModule.forRoot( [ { path: '', component: ShellPage }, { path: 'search', loadChildren: './search/search.module#SearchModule' }, { path: 'detail/:id', loadChildren: './track-detail/track-detail.module#TrackDetailModule' }, ], { preloadingStrategy: PreloadAllModules } )

Slide 17

Slide 17 text

[ { path: '', redirectTo: '/tutorial', pathMatch: 'full' }, { path: 'app', loadChildren: './pages/tabs-page/tabs-page.module#TabsModule' }, { path: 'tutorial', loadChildren: './pages/tutorial/tutorial.module#TutorialModule', canLoad: [CheckTutorial] } ]

Slide 18

Slide 18 text

import { Injectable } from '@angular/core'; import { CanLoad, Router } from '@angular/router'; import { Storage } from '@ionic/storage'; @Injectable({ providedIn: 'root' }) export class CheckTutorial implements CanLoad { constructor(private storage: Storage, private router: Router) {} canLoad() { return this.storage.get('ion_did_tutorial').then(res  { if (res) { this.router.navigate(['/app', 'tabs', 'schedule']); return false; } else { return true; } }); } }

Slide 19

Slide 19 text

Group common routes in one module Preloading Strategy for loading times

Slide 20

Slide 20 text

THE RIGHT LIBRARIES moment 335KB, Core + Locales date-fns/esm (format) 9KB, ESModule

Slide 21

Slide 21 text

THE RIGHT LIBRARIES lodash 70KB lodash-es (without) 5KB

Slide 22

Slide 22 text

This is how Ionic works Each component, a single ES-Module IonicModule will fetch as needed FUN FACT

Slide 23

Slide 23 text

THE RIGHT LIBRARIES source-map-explorer
 http://bit.ly/2vNgly4 Angular CLI Budgets
 http://bit.ly/2ATuiA5

Slide 24

Slide 24 text

MAKE IT CACHE

Slide 25

Slide 25 text

SERVICE WORKER Proxy for the network Intercepts out-going and incoming data Caching and much more

Slide 26

Slide 26 text

if ('serviceWorker' in navigator) { navigator.serviceWorker.register('service-worker.js') .then(() => console.log('service worker installed')) .catch(err => console.log('Error', err)); }

Slide 27

Slide 27 text

self.addEventListener('activate', (event) => { event.waitUntil( // then create our named cached caches .open('my-sw-cache') .then(function(cache) { // once created, lets add some local resources return cache.addAll([ './build/main.js', './build/main.css' ]); }) .then(function(){ console.log('Service worker is ready, and assets are cached'); })); }); https://serviceworke.rs

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

A lot of overhead Can be complex Best to use a library

Slide 30

Slide 30 text

npm install @angular/service-worker

Slide 31

Slide 31 text

JSON driven approach Precache, Lazy, External Caching Strategy and age

Slide 32

Slide 32 text

{ "index": "/index.html", "assetGroups": [ { "name": "app", "installMode": "prefetch", "resources": { "files": ["/index.html", "/*.css", "/*.js"] } }, ], "dataGroups": [...] }

Slide 33

Slide 33 text

import { ServiceWorkerModule } from '@angular/service-worker'; @NgModule({ declarations: [AppComponent], imports: [ ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production }), BrowserModule,

Slide 34

Slide 34 text

Check for updates with SwUpdate Send Push Notifications with SwPush

Slide 35

Slide 35 text

BUT WAIT, THERE'S MORE

Slide 36

Slide 36 text

ng add @angular/pwa

Slide 37

Slide 37 text

Creates Service Worker Auto-imports ServiceWorkerModule Enabled for Prod builds

Slide 38

Slide 38 text

MAKE IT LAST

Slide 39

Slide 39 text

MANIFEST JSON file for App assets Icons, theme, and name Display mode for home screen

Slide 40

Slide 40 text

{ "name": "ngAtlanta", "short_name": "ngAtl", "start_url": "/app/tabs/schedule", "display": "standalone", "orientation": "portrait-primary", "icons": [ { "src": "assets/img/appicon.png", "sizes": "192x192", "type": "image/png" } ], "background_color": "#222428", "theme_color": "#222428" }

Slide 41

Slide 41 text

Slide 42

Slide 42 text

PART OF @angular/pwa Adds manifest to project Makes changes to index.html Includes sample icons

Slide 43

Slide 43 text

OK, SO HOW DID WE DO?

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

BONUS MATERIAL

Slide 46

Slide 46 text

@ng-toolkit:
 Schematics for Universal ngx-build-modern
 ES2015/ES5 builds

Slide 47

Slide 47 text

The Average web app loads in 14 seconds

Slide 48

Slide 48 text

THANK YOU github.com/mhartington/ng-atl-conf ion-ng-atl.firebaseapp.com