by Gerard Sans | @gerardsans
SANS
GERARD
Spoken at 162 events in 37 countries
Reliable
Storage
Native-like Features
Great User Experience
Offline
Ready
Web App
Manifest
Service
Worker
Security
(HTTPS)
index.html
Cache
Hosting
Service
Worker
OFFLINE
app.js
logo.png
app.js
logo.png
app.js
logo.png
app.js
logo.png
$ ng add @angular/pwa
ngsw-config.json (added)
src/assets/icons/icon-*.png (added)
src/manifest.webmanifest (added)
angular.json (updated)
index.html (updated)
app.module.ts (updated)src/app.component.ts
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AmplifyDatastore</title>
  <link rel="icon" type="image/x-icon" href="favicon.ico">
+  <link rel="manifest" href="manifest.webmanifest">
+  <meta name="theme-color" content="#1976d2">
</head>
<body>
  <app-root></app-root>
+  <noscript>Please enable JavaScript.</noscript>
</body>
</html>
src/app.component.ts
import { ServiceWorkerModule } from '@angular/service-worker';
import { env } from '../environments/environment';
@NgModule({
  imports: [
    ServiceWorkerModule.register('ngsw-worker.js', { 
      enabled: env.production 
    })
  ],
})
export class AppModule { }
src/app.component.ts
$ ng build --prodsrc/app.component.ts
└── dist
  ├── assets/icons
  ├── favicon.ico
  ├── index.html
  ├── manifest.webmanifest
  ├── safety-worker.js
  ├── ngsw.json
  └── ngsw-worker.js$ npm i -g http-server 
$ http-server dist/amplify-datastore -o{
  "index": "/index.html",
  "assetGroups": [ 
     { 
       "name": "app",
     }, 
     { 
       "name": "assets", 
     }
  ]
}src/app.component.ts
{
 "name": "app", 
 "installMode": "prefetch", // prefetch | lazy
 "resources": {
   "files": [ 
     "/favicon.ico", 
     "/index.html", 
     "/manifest.webmanifest", 
     "/*.css", 
     "/*.js"
   ],
   "urls": [ 
     "https://aws-amplify.github.io/images/Logos/Amplify-Logo-White.svg"
   ]
 } 
}src/app.component.ts
{
  "name": "assets", 
  "installMode": "lazy", 
  "updateMode": "prefetch",
  "resources": {
    "files": [ 
      "/assets/**", 
      "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
    ]
  }
}
src/app.component.ts
// <div *ngIf="offline">You are offline.</div>
// app.component.ts
@Component(...)
export class AppComponent implements OnInit {
  offline : boolean = false;
  ngOnInit() {
    merge<boolean>(
      fromEvent(window, 'offline').pipe(mapTo(true)),
      fromEvent(window, 'online').pipe(mapTo(false)),
      of(!navigator.onLine)
    ).subscribe(offline => this.offline = offline);
  }
}src/app.component.ts