by Gerard Sans | @gerardsans
Big time PWA
using GraphQL and
Amplify DataStore
Big time PWA
using GraphQL and
Amplify DataStore
SANS
GERARD
Developer Advocate AWS
Developer Advocate AWS
International Speaker
Spoken at 160 events in 37 countries
What is Offline first?
Offline First for Web
Reliable
Storage
Native-like Features
Great User Experience
Offline
Ready
Progressive Web Apps
Reach
Capabilities
Native
Applications
PWA
Applications
Web/SPA
Applications
PWA Core Requirements
Web App
Manifest
Service
Worker
Security
(HTTPS)
Service Worker Online
index.html
Cache
Hosting
Service
Worker
app.js
app.js
app.js
logo.png
logo.png
logo.png
app.js
logo.png
app.js
logo.png
Service Worker Offline
index.html
Cache
Hosting
Service
Worker
OFFLINE
app.js
logo.png
app.js
logo.png
app.js
logo.png
app.js
logo.png
AWS AMPLIFY
Fullstack Serverless
🦄
🌩️
Web and Mobile support
preview
AWS Amplify
Amplify Framework
- Open source
- Categories based
- Opinionated
- Scape hatches
Developer Tools
- Amplify CLI
- Create & manage AWS Services
- Multiple environments
- Mocks & local testing
- Plugins (video, docs, ttl)
amplify update
category
amplify
init
amplify
add
category
amplify
push
Amplify CLI development
AWS Amplify Console
- Auto-deploy on commit
- Seamless CD/CI, deploy globally, custom domains, branch-based, atomic, secured
- Supports GitHub, Bitbucket, GitLab, CodeCommit
- Drag&drop folder or zip
interactions
storage
notifications
auth
analytics
function
api
hosting
xr
transcribe
translate
polly
rekognition
comprehend
Chatty
Chatty App
AppSync
GraphQL
$ amplify init
$ amplify add auth
$ amplify add api
$ amplify push
src/app.component.ts
Amplify CLI commands
type Chatty @model {
id: ID!
user: String!
message: String!
createdAt: AWSDateTime
}
src/app.component.ts
Chatty GraphQL Schema
Amplify DataStore Offline
Amplify DataStore Online
import { DataStore } from "@aws-amplify/datastore";
import { Chatty } from "./models";
await DataStore.save(new Chatty({
user: "gsans",
message: "Hi everyone!👋",
createdAt: new Date().toISOString()
}))
src/app.component.ts
Creating a Message
import { DataStore, Predicates } from "@aws-amplify/datastore";
import { Chatty } from "./models";
const msg = await DataStore.query(Chatty, Predicates.ALL);
src/app.component.ts
Querying data
Make it
a PWA!
$ 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
Run PWA plugin
<!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
index.html
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
app.module.ts
$ ng build --prod
src/app.component.ts
Test your PWA
└── 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
ngsw-config.json
{
"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
ngsw-config.json (assetGroup: app)
{
"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
ngsw-config.json (assetGroup: assets)
Chatty
PWA
Web, Mobile and Desktop
Add to home screen
Passes Lighthouse Test
99% Offline-ready
- Survives offline reload
- Stores messages while offline
- Shares messages when back online
- User doesn't know if App is offline
// <div *ngIf="offline">You are offline.</div>
// app.component.ts
@Component(...)
export class AppComponent implements OnInit {
offline : boolean = false;
ngOnInit() {
// Registering datastore hub
Hub.listen('datastore', message => {
const { event, data } = message.payload;
if (event === 'networkStatus') {
this.offline = !data.active;
}
})
}
}
src/app.component.ts
Improve Offline UX
- Faster (pre-cached)
- Online/Offline
- Full screen app
- Browser/Mobile/Desktop
- Web/Native-like features
- Slower
- Online
- Tab in browser
- Browser
- Web features
Web/SPA vs PWA
Try it!
amplify-datastore-chatty-pwa-angular
amplify-datastore-chatty-angular (workshop)
Big time PWA using GraphQL and Amplify DataStore
By Gerard Sans
Big time PWA using GraphQL and Amplify DataStore
Offline-first apps need to support: intermittent connectivity, transition seamlessly between online and offline states, reliable CRUD on-device data, data synchronisation and data conflict resolution to enable real-time collaboration. Amplify DataStore is an on device persistent repository for interacting with local data and able to automatically synchronize via GraphQL. Using Amplify DataStore will allow us to implement offline-first while using a simple programming model.
- 2,494