SlideShare ist ein Scribd-Unternehmen logo
1 von 152
Downloaden Sie, um offline zu lesen
PWA: Progressive Web Apps
Kenneth R. Christiansen
Hi! I am Kenneth
Our team mission
Move the Web Platform forward
➫ Make the web run super fast on Intel hardware
➫ Keep the open web relevant and make sure Intel has influence on the direction
➫ Align the web with Intel strategies, and take advantage of the web
➫ Identify industry trends and respond
➫ Ensure good collaboration with our partners such as Google and Apple
Today we will talk about something that will keep
the web relevant in years to come
And which might make Windows 10 and
Chromebooks much more relevant as well.
➫ Intro to PWAs, and why it matters
➫ Manifest
➫ The Service Worker
➫ Ensuring a fast load time
➫ Push notifications
➫ Background sync
➫ Web Share
➫ Sign in and credential Management
Outline
Introducing
https://developers.google.com/web/progressive-web-apps/
Progressive Web Apps start at the URL bar
The idea is that any site can over time with proper engagement,
can progressively turn into a more powerful and integrated
experience
Or people can manually opt in to that experience by installing
manually from eg. a store
The basic premise
Progressive Web Apps offers the best of the modern web
They work reliable, they load fast and are responsive
The basic premise
Reliable, fast loading, responsiveness
Progressive Web Apps and often abbreviated as PWAs
A community logo exists:
https://medium.com/samsung-internet-dev/we-now-have-a-community-approved-progressive-web-apps-logo-823f212f57c9
The basic premise
People the web because it is ephemeral
● Sites' resources (cache etc) gets removed when not visited regularly, depending on cache pressure
● No need to worry whether apps will update in the background even when you never use them, or just
fill up your storage
The basic idea
You visit many sites a month, most never again
But some you visit again and again, you engage with them
The basic idea
You can manually add sites to home screen
via a menu
But when you reach an engagement threshold,
sites can prompt you to install them*
* On Chrome, Opera, Firefox (mobile) and Samsung Internet so far
The basic idea
The added app now appears on home screen and in launcher
The basic idea
When you launch, the app starts as a separate app,
indistinguible from any other native apps
The basic idea
https://www.youtube.com/watch?v=Dsv5NT4PYG0
The best of the web!
Great reach, low friction
safe
ephemeral
(deep) linkable
indexable
composable
PWA are applications created with web technology, who look
and act like native applications, but are being run by the build
in browser.
Summary
PWAs can be installed in different ways, for instance via an
app store or from the browser when visiting a site.
The behavior depends on the OS and browser.
Summary
PWAs are just modern websites, no special API access, but
they do get special treatment
➫ Browser chrome is configurable
➫ More integrated with host OS (optional): orientation lock, icon in launcher, no chrome
➫ Additional rights due to engagement:
○ autoplay video with sound
○ ask for persistent storage
○ more to come
➫ Some features like being a share target can only work with installed apps
Summary
Deep dive!
{
"short_name": "Flipkart",
"name": "Flipkart Lite",
"start_url": "/?start_url=homescreen",
"display": "standalone",
"orientation": "portrait",
"icons": [{
"src": "icons/icon-192.png",
"sizes": "192x192",
"type": "image/png"
}]
}
M A N I
F E S T_
101
➫ W3C working draft standard
➫ Allows defining metadata associated with a web app
➫ https://www.w3.org/TR/appmanifest/
➫ Useful for packaging
Web App Manifest
Add site to home screen
➫ Has a unique icon and name in
the launcher / home screen
➫ Can display splash-screen to
the user when loading
➫ Hides the browser UI (if
desired) to feel like a native
app
Describe launch style
{
"short_name": "SSG Portal",
"name": "Intel SSG Portal",
"start_url": "/?start_url=homescreen",
"display": "standalone",
"orientation": "portrait",
...
}
{
...
"icons": [{
"src": "images/touch/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
}, {
"src": "images/touch/apple.png",
"sizes": "152x152",
"type": "image/png"
}]
}
Describe your assets
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope Entry point and URLs which are considered part of the app
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker Service Worker associated with the app, especially for stores
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language) Metadata for text and iconography
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description Info for app launcher, install dialogs
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources Icons and screens for app launcher, store
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id Store related information, like universal age rating
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation Display style (eg. fullscreen) and orientation lock
➫ theme_color and background_color
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color UI color like for splashscreen & app switcher
➫ related_applications and prefer_related_applications
Available values
➫ start_url and scope
➫ serviceworker
➫ dir (direction) and lang (language)
➫ name, short_name and description
➫ icons, screenshots image resources
➫ categories and iarc_rating_id
➫ display and orientation
➫ theme_color and background_color
➫ related_applications and prefer_related_applications Refer to store apps
Available values
<link rel="manifest" href="/manifest.json">
Refer to the manifest inside your HTML resources
Test your manifest using Chrome DevTools
Chrome DevTools
➫ Manifest can be extended by other specs to give more
functionality - check Web Share Target later
➫ The manifest entries and values are integrated in the new
Web Packaging spec:
○ https://tools.ietf.org/id/draft-yasskin-dispatch-web-packaging-00.html#rfc.section.2.4
○ https://amphtml.wordpress.com/2018/01/09/improving-urls-for-amp-pages/
○ The parsed manifest consists of the set of signing-certificates and the manifest CBOR item. The items in
manifest[“metadata”] SHOULD be interpreted as described in the [appmanifest] specification.
Web App Manifest
navigator.serviceWorker 101
Promises and async/await
But first...
➫ The Promise object is used for async calculations
➫ Represents a values which is available now, in the future or never
➫ Promise.resolve() returns a resolved promise, Promise.reject() a failed promise
➫ Much more readable code than callback hell
new Promise( /* executor */ function(resolve, reject) { ... }
);
Async code with promises
pending: initial state, not fulfilled or rejected
fulfilled: means that the operation is completed with success
rejected: means that the operation failed
Promises can be chained:
The three states
Creation and usage of promises
const p3 = new Promise(function (resolve, reject) {
if (/* condition */ ) {
resolve(/* value */ ); // fulfilled successfully
}
else {
reject(/* reason */ ); // error, rejected
}
});
function after(time) {
if (typeof time !== "number" )
return Promise.reject("Not a number!" ); // static method
return new Promise(resolve => {
setTimeout (_ => resolve(), time);
// resolve/reject can be async
});
}
after(1000).then(_ => console.log("hi 1 sec later" ))
// an immediately resolved promise
const p2 = Promise.resolve("foo");
// can get it after the fact, unlike events
p2.then(res => console.log(res));
const p = new Promise(function (resolve, reject) {
setTimeout (() => resolve(4), 2000);
});
// handler can't change promise, just value
p.then(res => {
res += 2;
console.log(res);
});
// still gets 4
p.then(res => console.log(res));
Examples
.then() and .catch()
// Throw is the same as calling reject
let p1 = new Promise((resolve, reject) => {
if (true)
throw new Error("rejected!");
else
resolve(4);
});
// A .catch() at the end catches all rejections
p1.then((val) => val + 2)
.then((val) => console.log("got", val))
.catch((err) => console.log("error: ",
err.message));
// => error: rejected!
p.then(val => console.log("fulfilled:", val),
err => console.log("rejected: ", err));
// The following two gives the same result:
p.then(val => console.log("fulfilled:", val))
.catch(err => console.log("rejected:", err));
p.then(val => console.log("fulfilled:", val))
.then(null, err => console.log("rejected:", err));
Examples
➫ Promise.all([p1, p2, ...]) -> resolves if all individual promises resolve and first at
that point
➫ Promise.race([p1, p2, ...]) -> resolves when the first promise resolves
Notice that .then() always returns a promise!
Async with promises
const p = new Promise.resolve().then(_ => console.log("hi")).then(_ => …)
Pros
➫ Write async code in a synchronous way, without much indentation and with exception handling in one
place
➫ Helps unify async APIs and wrap existing APIs with promises
➫ Guarantees that there will be no race-conditions and that future values represented by the promise are
immutable (which is not the case with callbacks and events)
"Cons"
➫ Promises cannot be cancelled
➫ If you don't handle their rejects/exceptions, they get swallowed
➫ Multiple .then() mixes with lots of arrow functions can be hard to read - more about async/await later
Summary
➫ Easier way to work with promises
➫ Functions can be marked "async" and then you can "await" on functions
returning promises
➫ Doesn't work top-level as you cannot mark it async
Async / await
Without and with async / await
function logFetch (url) {
return fetch(url)
.then(response => response .text())
.then(text => {
console.log(text);
}).catch(err => {
console.error('fetch failed' , err);
});
}
async function logFetch (url) {
try {
const response = await fetch(url);
console.log(await response .text());
}
catch (err) {
console.log('fetch failed' , err);
}
}
Examples
More examples
// wait ms milliseconds
function wait(ms) {
return new Promise(r => setTimeout (r, ms));
}
async function hello() {
await wait(500);
return 'world';
}
// Careful! Avoid going too sequential
async function parallel () {
const wait1 = wait(500); // Start a 500ms timer asynchronously…
const wait2 = wait(500); // …meaning this timer happens in
parallel.
await wait1; // Wait 500ms for the first timer…
await wait2; // …by which time this timer has already finished.
return "done!";
}
async function f() {
return 1;
}
async means :
➫ An async function always returns a promise.
➫ If the code has return <non-promise> in it, then automatically wraps it
into a resolved promise with that value. (the same happens in
promise chains with .then())
// fails!
let value = await f;
await means :
➫ JavaScript wait until that promise settles and returns its result
➫ Doesn’t work in top level code as stated before
More about async / await
Prerequisite: fetch
fetch(url).then(r => r.json())
.then(data => console.log(data))
.catch(e => console.log("Booo"))
Fetch is:
➫ a massive improvement on XMLHttpRequest
➫ Support request options (e.g. CORS, headers)
➫ Can send credentials together with the request
Proxy between web apps and the network (when available)
Web
Browser
Service
Worker
Remote
Server
/api /api
Service Workers are flexible!
➫ They are a specialized web worker
➫ Programmable!
➫ Choose your own caching mechanism
➫ Even different one depending on URL!
Service Workers work on second load
➫ Progressive enhancement
➫ Site must work without
➫ Provides an update mechanism
Registering a Service Worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ',
registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}
Install a Service Worker
self.addEventListener('install', function(event) {
// Perform install steps
});
Inside the handler you need to:
➫ Open a cache
➫ Cache the files
➫ Confirm whether all the required assets are cached or not
const CACHE_NAME = 'my-site-cache-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/script/main.js'
];
self.addEventListener('install', function(event) {
// Perform install steps
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Opened cache');
return cache.addAll(urlsToCache);
})
);
});
Install a Service Worker
Caching resources
When caching should be done?
Ideal for
➫ CSS, Images, Fonts, JS
➫ Mandatory stuff to make your site
functional
On install
Ideal for
➫ Clean up and migration
➫ If you have a previous SW, good time
to cleanup old caches, db…
➫ Keep the code lean
On activate
Ideal for
➫ If the whole site can't be taken offline, you may allow the user to select the content
they want available offline (e.g. video, article…)
➫ Give the user “Read later”, “Save for offline”
➫ Fetch what you need and put in the cache
As a result of user interaction
Ideal for
➫ Frequently updating resources such as a user's inbox, or article contents.
➫ If a request doesn't match anything in the cache, get it from the network, send it to
the page and add it to the cache at the same time.
As a result of network response
Ideal for
➫ Frequently updating resources where having the very latest version is non-essential
○ Eg. avatars can fall into this category
➫ If there's a cached version available, use it, but fetch an update for next time
Stale-while-revalidate
Ideal for
➫ Content relating to the notification
➫ Update cache here before the user
clicks to provide a great offline
experience
As a result of a push message
Ideal for
➫ Non-urgent updates such as social timelines or news articles.
➫ Cache when your SW is woken up by the sync event
As part of background sync
Ensuring a fast loading time
➫ Lots of data down the wire
➫ Multiple entries to your app (main page, deep link, embedding in social media)
➫ Not all resources are needed always (per view, per language, per log in)
➫ Many small requests are bad for performance
➫ Some resources are more expensive byte-wise (ie JS has a high parsing cost)
The problem
➫ Optimize images - https://images.guide/
➫ Know what libraries you use and why #usetheplatform
○ Newer libraries like preact and lit-html-(element) are quite tiny
○ Often the platform does what you need, and if not, tiny polyfills often exist
➫ Compress and tree-shake your deployment code
The problem
➫ Push critical resources for the initial URL route
➫ Render the initial route
➫ Pre-cache remaining routes.
➫ Lazy-load and create remaining routes on demand.
Focus on minimum time to interactive and maximum caching
PRPL Pattern (Pillars)
export function sayName(name) {
console.log(`Hello ${name}`);
}
➫ Separate code into modules
➫ Import and export symbols
➫ Support for sync and async loading
➫ Improves code organization
➫ Great for external dependencies
mymodule.js
import { sayName } from './mymodule.js';
sayName('Sam');
// Hello Sam
app.js
ES Modules
export function sayName(name) {
console.log(`Hello ${name}`);
}
➫ Load on demand
➫ Good for lazy loading
mymodule.js
<script type="module">
async function greet() {
const myModule = await import('./mymodule.js');
myModule.sayName('Sam');
}
greet(); // Hello Sam
</script>
app.js
ES Modules - dynamic loading
➫ ES modules work for JavaScript only
➫ You can distribute HTML and CSS as JavaScript!
○ Strings and string templates in JS bypass the JS parser (and its slowness)
○ HTML and CSS is represented as strings anyway, so not a problem
○ JSX (as used by React) is converted to function calls, so slower than text
○ New approaches like lit-html and hyperHTML use string template literals to do the same as
JSX and still be as fast as HTML/CSS (except the optional JS parts)
ES Modules
Example using lit-html
Great IDE support in Visual Studio Code
Example of CSS and HTML distributed like JS
How you can bundle today?
The old way
➫ Global namespace is polluted
➫ Order of loading become important
➫ Have to make sure the main scripts are loaded before using them
Multiple bunders exists!But it is still early days
rollup.js
➫ Bundles code together
➫ Can hook out to other tools and analyze code to eliminate dead code
➫ Often does code-splitting into separate JS files
➫ Often requires a lot of configuration
○ Entry points, chunking etc
Bundlers
➫ Different bundlers today allows to analyze code and do dead code elimination
➫ By providing entry points* tools can automatically split code into modules and even
identify common chunks
➫ Some downsides
○ As things are up front, it is hard to adjust the splitting when things change
○ Re-chunking means throwing away code that didn't change from browser cache
➫ On the fly splitting could be better, but requires the dev to modularize the code
○ Good use-case for web components
○ Be aware with tree-shaking
○ You might tree-shake libraries and hash encode them, but components should be small and not
tree-shaken
*www.mysite.org vs www.mysite.org/profile etc
Code splitting and tree-shaking
➫ There is a protocol overhead for each request compared to a single
concatenated file
➫ The compression of the single large file is better than many small files
➫ Servers are slower serving many small files than a single large file
Realization: Servers are faster at sending few, large files
Server
Request index.html
Receive index.html
Request style.css
Receive style.css
Request index.html
Receive index.html
Receive style.css
Receive app.js
HTTP 1.x HTTP 2.0
➫ Server Push lets the server bundle and send assets alongside a request
○ Requires server logic
○ Allows the server to do on-demand code splitting/bundling with ES modules
○ Doesn't require everything to be distributed like JS
➫ Better caching in the browser
1
2
3
4
1
2
HTTP 2.0 Server Push
Browser Browser Server
➫ Entrypoint needs to be very small
➫ Shell or app-shell includes the top-level app logic, router, and so on
➫ Lazily loaded fragments of the app (e.g. additional views, menus…)
index.html
app.js
view1.js view2.js
view1 dependencies shared dependencies view2 dependencies
Shell
Entrypoint
Fragment
Dependency tree
Shell bundle Fragment bundle
index.html
app.js
view1.js view2.js
view1 dependencies shared dependencies view2 dependencies
Shell
Entrypoint
Fragment
Bundled build
Fragment bundle
➫ Rely on CSS, HTML and ES modules
➫ Load on demand
➫ Create your own web components
➫ Share resources with hashes in names because of caches
➫ Have the server and service worker work together
➫ Do code splitting and bunding on demand
○ unbundled at received so better for caching
The dream
https://github.com/Polymer/prpl-server-node
➫ Does exactly all of this
➫ Originally written for Polymer, and HTML imports (now dead standard)
➫ Works with Service Worker and ES Modules
➫ Works as a Node server or via Cloud Functions
➫ Still not battle tested enough, gone through changes due to deprecation of
HTML modules
PRPL Server Node
Push Notifications
Two complementary APIs
Web Push API and Notifications API
Browser doesn’t need to
be running to receive
messages, thanks to
Service Worker
Web Push Notifications
How does Push work?
Get permission
to send notifications
Subscribe and get
PushSubscription
Send PushSubscription
to your server
Client side
Overall view
You've got a message!
function askPermission () {
return new Promise(function(resolve, reject) {
const permissionResult = Notification .requestPermission (function(result) {
resolve(result);
});
if (permissionResult ) {
permissionResult .then(resolve, reject);
}
})
.then(function(permissionResult ) {
if (permissionResult !== 'granted') {
throw new Error('We weren't granted permission.' );
}
});
}
Request permission
But when to prompt?
➫ Avoid asking early unless
necessary (chat, mail apps)
➫ Double permission pattern:
Allows the user to decide
without permanently blocking
your site
When to prompt?
Showcase of how to do it
Specific - contextual
User initiated
function subscribeUserToPush() {
return navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
const subscribeOptions = {
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeIHBQFLXYp5Nksh8U'
)
};
return registration.pushManager.subscribe(subscribeOptions);
})
.then(function(pushSubscription) {
console.log('Received PushSubscription: ', JSON.stringify(pushSubscription));
return pushSubscription;
});
}
Subscribe to push notifications
{
"endpoint": "https://random-push-service.com/some-kind-of-unique-id-1234/v2/",
"keys": {
"p256dh" :"BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_Ts1XbjhazAkj7I99e8QcYP7DkM=",
"auth" : "tBHItJI5svbpez7KI4CCXg=="
}
}
Example of subscription
const subscriptionObject = {
endpoint: pushSubscription.endpoint,
keys: {
p256dh: pushSubscription.getKeys('p256dh'),
auth: pushSubscription.getKeys('auth')
}
};
Send subscription to server
function sendSubscriptionToBackEnd (subscription ) {
return fetch('/api/save-subscription/' , {
method: 'POST',
headers: {
'Content-Type' : 'application/json'
},
body: JSON.stringify(subscription )
})
.then(function(response) {
if (!response.ok) {
throw new Error('Bad status code from server.' );
}
return response.json();
})
.then(function(responseData ) {
if (!(responseData .data && responseData .data.success)) {
throw new Error('Bad response from server.' );
}
});
}
Send subscription to server
app.post('/api/save-subscription/' , function (req, res) {
if (!isValidSaveRequest (req, res)) {
return;
}
return saveSubscriptionToDatabase (req.body)
.then(function(subscriptionId ) {
res.setHeader('Content-Type' , 'application/json' );
res.send(JSON.stringify({ data: { success: true } }));
})
.catch(function(err) {
res.status(500);
res.setHeader('Content-Type' , 'application/json' );
res.send(JSON.stringify({
error: {
id: 'unable-to-save-subscription' ,
message: `The subscription was received but
we were unable to save it to our database.`
}
}));
});
});
On the server
Sending Push Notifications
➫ Make a POST request to a push notification service (e.g. APNS, Firebase Cloud
Messaging)
➫ Use Voluntary Application Server Identification (VAPID)
➫ Encrypt the data to pass to the application
➫ Send!
- Node.JS server -> NodeJS Web Push Library
- Cloud functions (e.g. Firebase)
Sending push notifications - Prerequisite
const vapidKeys = {
publicKey:
'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U ',
privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls '
};
webpush.setVapidDetails(
'mailto:web-push-book@gauntface.com',
vapidKeys.publicKey,
vapidKeys.privateKey
);
Tell webpush about your app keys
app.post('/api/trigger-push-msg/', function (req, res) {
return getSubscriptionsFromDatabase()
.then(function(subscriptions) {
let promiseChain = Promise.resolve();
for (let i = 0; i < subscriptions.length; i++) {
const subscription = subscriptions[i];
promiseChain = promiseChain.then(() => {
return triggerPushMsg(subscription, dataToSend);
});
}
return promiseChain;
})
... // return response HTTP 500
}
Trigger a push message
const triggerPushMsg = function(subscription, dataToSend) {
return webpush.sendNotification(subscription, dataToSend)
.catch((err) => {
if (err.statusCode === 410) {
return deleteSubscriptionFromDatabase(subscription._id);
} else {
console.log('Subscription is no longer valid: ', err);
}
});
};
Trigger a push message
Back to the client
Handling of Push Events
self.addEventListener('push', function(event) {
if (event.data) {
console.log('This push event has data: ', event.data.text());
} else {
console.log('This push event has no data.');
}
});
➫ Browser doesn’t need to be opened, your SW will be woken up
➫ You can get the notification data with event.data.json() or event.data.text()
Inside your Service Worker
self.addEventListener('push', function(event) {
const promiseChain = self.registration.showNotification('Hello, World.');
event.waitUntil(promiseChain);
});
➫ showNotification() returns a promise that resolve when notification is displayed
➫ Use waitUntil to tell the browser to keep the SW running until the promise has resolved
Show your notification
<ServiceWorkerRegistration>.showNotification(<title>, <options>);
{
"//": "Visual Options",
"body": "<String>",
"icon": "<URL String>",
"image": "<URL String>",
"badge": "<URL String>",
"vibrate": "<Array of Integers>",
"sound": "<URL String>",
"dir": "<String of 'auto' | 'ltr' | 'rtl'>",
...
➫ Title is a string
➫ Options can be any of the following:
Customize your notification
Customize your notification
Notifications Behaviors
self.addEventListener('notificationclick', function(event) {
const clickedNotification = event.notification;
clickedNotification.close();
// Do something as the result of the notification click
const promiseChain = doSomething();
event.waitUntil(promiseChain);
});
➫ Notification that was clicked can be access with event.notification
➫ Remember to use waitUntil while your code is busy
Handling user interactions with the notification
const title = 'Actions Notification';
const options = {
actions: [
{
action: 'coffee-action',
title: 'Coffee',
icon: '/images/demos/action-1-128x128.png'
},
{
action: 'doughnut-action',
title: 'Doughnut',
icon: '/images/demos/action-2-128x128.png'
},
...
registration.showNotification(title, options);
Add notification actions
self.addEventListener('notificationclick', function(event) {
if (!event.action) {
// Was a normal notification click
console.log('Notification Click.');
return;
}
switch (event.action) {
case 'coffee-action':
console.log('User ❤ 's coffee.');
break;
case 'doughnut-action':
console.log('User ❤ 's doughnuts.');
Break;
...
Handling notification actions
self.addEventListener('notificationclose', function(event) {
const dismissedNotification = event.notification;
const promiseChain = notificationCloseAnalytics();
event.waitUntil(promiseChain);
});
User dismiss the notification
self.addEventListener('notificationclick', function(event) {
const examplePage = '/demos/notification-examples/example-page.html';
const promiseChain = clients.openWindow(examplePage);
event.waitUntil(promiseChain);
});
Opening a window
* And more at https://developers.google.com/web/fundamentals/push-notifications/common-notification-patterns
Common patterns
Background Sync
What is background sync?
➫ A way to not rely on having a stable internet
connection
➫ A way to defer network related operations to
when the connection is available
➫ Depends on Service Worker
➫ Can operate even when application is closed
navigator.serviceWorker.ready.then(function(registration) {
registration.sync.register('outbox').then(function() {
// registration succeeded
}, function() {
// registration failed
});
});
➫ The string argument to register operates like a notification's tag. It is passed to the
service worker event.
Request a sync
self.addEventListener('sync', function(event) {
if (event.tag == 'outbox') {
event.waitUntil(sendEverythingInTheOutbox());
}
});
➫ sync will fire when the user agent believes the user has connectivity.
➫ Use waitUntil to tell that the sync event is ongoing to keep the service worker
alive if possible
Respond a sync
Sharing and caring
Share data and URLs with other apps
and become a share target yourself
Web Share API
➫ Super simple API allowing to share text (a text string) and/or a URL
➫ Allows setting a title as well, but it might be ignored by the client
➫ https://wicg.github.io/web-share/
if (navigator.share) {
navigator.share({
title: 'Web Fundamentals',
text: 'Check out Web Fundamentals',
url: 'https://developers.google.com/web',
})
.then(_ => console.log('Successful share'))
.catch(err => console.log('Error:', err));
}
➫ Invokes the native share dialog so that the
user can select who to share with
➫ Only work on HTTPS, following a user
action (e.g. click)
Using the Web Share API
Web Share Target API
➫ Make the PWA become a share target
➫ Application has to be added by user to system
○ eg. add to homescreen / store install
➫ https://wicg.github.io/web-share-target/
➫ Extension to Web App Manifest
Sign-in and credential
management
What is the sign in and credential management API?
➫ Removes friction from sign-in flows - Users can be automatically signed back
➫ Allows one tap sign in with account chooser - Users can choose an account in a
native account chooser.
➫ Stores credentials - Your application can store either a username and password
combination or even federated account details. These credentials can be synced
across devices by the browser.
if (navigator.credentials) {
if (!user.isSignedIn()) {
navigator.credentials.get({
password: true,
federated: {
providers: [
'https://accounts.google.com'
]
},
mediation: 'silent'
})
// ...
}
}
Sign-in users
}).then(c => {
if (c) {
switch (c.type) {
case 'password':
return sendRequest(c);
break;
case 'federated':
return gSignIn(c);
break;
}
} else {
return Promise.resolve();
}
})
Run authentication flow
}).then(profile => {
if (profile) {
updateUI(profile);
}
})
Update the user interface
How to evaluate?
How to know how I am performing with my PWA'ness
Lighthouse
Guiding you on the path towards
progressive web app-iness.
goo.gl/zzopnG
Sonarwhal
Linting tool for the web, built by Microsoft
https://sonarwhal.com/
https://sonarwhal.com/docs/user-guide/rules/#pwas
Browser support?
Is this all Chrome and mobile only?
Google is a big supporter
➫ Very good support on Android
➫ Working on desktop + Chrome OS support
➫ Working on extending standards and matching Electron
features on desktop
PWAs on Android
➫ Requires HTTPS, Offline experience, manifest
➫ Engagement criteria
➫ Add to homescreen dialog
➫ Installs generated Web APK from Google server
PWAs in the Play Store?
➫ Not directly supported
➫ New Trusted Web Activity
○ Abide to Play store rules (payment etc)
○ Needs a file on server linking to app to show relationship
○ Runs in Chrome (not WebView) like Custom Tabs
○ Can be extended in Java with a onmessage/postmessage API
Early preview of desktop support
Early preview of desktop support
Early preview of desktop support
ServiceWorker
Cache API
Push API
Manifest
Microsoft is all-in on PWAs
Early preview of Windows support
https://mobile.twitter.com/kirupa/status/959175077836111872/video/1
Microsoft PWA support is strategic
➫ Deeply integrated into Windows
➫ Web Assembly allows native code to run at near native
speed on the web
➫ PWAs in store have access to all WinRT APIs
○ Polyfills will be available for some not-implemented APIs like Web
Bluetooth
PWAs in the Microsoft Store
PWAs in the Microsoft Store
What about
Apple?
ServiceWorker
Cache API
Push API
Manifest
Apple very recently started on PWA support
Thank you

Weitere ähnliche Inhalte

Was ist angesagt?

Salesforce Developer Garage Seattle: Force.com Canvas
Salesforce Developer Garage Seattle: Force.com CanvasSalesforce Developer Garage Seattle: Force.com Canvas
Salesforce Developer Garage Seattle: Force.com CanvasSalesforce Developers
 
Dive Deep Into the Force.com Canvas Framework
Dive Deep Into the Force.com Canvas FrameworkDive Deep Into the Force.com Canvas Framework
Dive Deep Into the Force.com Canvas FrameworkSalesforce Developers
 
Sencha Touch e PhoneGap: SouJava - IBM Maio 2013
Sencha Touch e PhoneGap: SouJava - IBM Maio 2013Sencha Touch e PhoneGap: SouJava - IBM Maio 2013
Sencha Touch e PhoneGap: SouJava - IBM Maio 2013Loiane Groner
 
Internship presentation
Internship presentationInternship presentation
Internship presentationWasim Shemna
 
Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015
Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015
Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015Suzzicks
 
Seamless Authentication with Force.com Canvas
Seamless Authentication with Force.com CanvasSeamless Authentication with Force.com Canvas
Seamless Authentication with Force.com CanvasSalesforce Developers
 
CapitolJS: Enyo, Node.js, & the State of webOS
CapitolJS: Enyo, Node.js, & the State of webOSCapitolJS: Enyo, Node.js, & the State of webOS
CapitolJS: Enyo, Node.js, & the State of webOSBen Combee
 
Internship Presentation 2 Web Developer
Internship Presentation 2 Web DeveloperInternship Presentation 2 Web Developer
Internship Presentation 2 Web DeveloperHemant Sarthak
 
Progressive Web Apps - Intro & Learnings
Progressive Web Apps - Intro & LearningsProgressive Web Apps - Intro & Learnings
Progressive Web Apps - Intro & LearningsJohannes Weber
 
Building Mobile Optimized Websites
Building Mobile Optimized WebsitesBuilding Mobile Optimized Websites
Building Mobile Optimized Websiteshaxorize
 
Basics to Search Engine Optimization & App Store Optimization with Pooja Goyal
Basics to Search Engine Optimization & App Store Optimization with Pooja GoyalBasics to Search Engine Optimization & App Store Optimization with Pooja Goyal
Basics to Search Engine Optimization & App Store Optimization with Pooja GoyalPooja Singla
 
How to optimize your blog for mobile traffic
How to optimize your blog for mobile trafficHow to optimize your blog for mobile traffic
How to optimize your blog for mobile trafficgroceryalerts
 
How to create your own WordPress plugin using WP App Studio
How to create your own WordPress plugin using WP App StudioHow to create your own WordPress plugin using WP App Studio
How to create your own WordPress plugin using WP App StudioeMarket Design
 
PWA - Progressive Web App
PWA - Progressive Web AppPWA - Progressive Web App
PWA - Progressive Web AppRobert Robinson
 
Getting started with PhoneGap
Getting started with PhoneGapGetting started with PhoneGap
Getting started with PhoneGapMihai Corlan
 
RESS: An Evolution of Responsive Web Design
RESS: An Evolution of Responsive Web DesignRESS: An Evolution of Responsive Web Design
RESS: An Evolution of Responsive Web DesignDave Olsen
 
JavaScript on HP webOS: Enyo and Node.js
JavaScript on HP webOS: Enyo and Node.jsJavaScript on HP webOS: Enyo and Node.js
JavaScript on HP webOS: Enyo and Node.jsBen Combee
 
Progressive web apps
Progressive web appsProgressive web apps
Progressive web appsAkshay Sharma
 

Was ist angesagt? (20)

Salesforce Developer Garage Seattle: Force.com Canvas
Salesforce Developer Garage Seattle: Force.com CanvasSalesforce Developer Garage Seattle: Force.com Canvas
Salesforce Developer Garage Seattle: Force.com Canvas
 
Dive Deep Into the Force.com Canvas Framework
Dive Deep Into the Force.com Canvas FrameworkDive Deep Into the Force.com Canvas Framework
Dive Deep Into the Force.com Canvas Framework
 
Sencha Touch e PhoneGap: SouJava - IBM Maio 2013
Sencha Touch e PhoneGap: SouJava - IBM Maio 2013Sencha Touch e PhoneGap: SouJava - IBM Maio 2013
Sencha Touch e PhoneGap: SouJava - IBM Maio 2013
 
Internship presentation
Internship presentationInternship presentation
Internship presentation
 
Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015
Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015
Why Deep Linking is the Next Big Thing: App Indexing - SMX East 2015
 
Smart Design
Smart Design Smart Design
Smart Design
 
Seamless Authentication with Force.com Canvas
Seamless Authentication with Force.com CanvasSeamless Authentication with Force.com Canvas
Seamless Authentication with Force.com Canvas
 
CapitolJS: Enyo, Node.js, & the State of webOS
CapitolJS: Enyo, Node.js, & the State of webOSCapitolJS: Enyo, Node.js, & the State of webOS
CapitolJS: Enyo, Node.js, & the State of webOS
 
Internship Presentation 2 Web Developer
Internship Presentation 2 Web DeveloperInternship Presentation 2 Web Developer
Internship Presentation 2 Web Developer
 
Ionic by Example
Ionic by ExampleIonic by Example
Ionic by Example
 
Progressive Web Apps - Intro & Learnings
Progressive Web Apps - Intro & LearningsProgressive Web Apps - Intro & Learnings
Progressive Web Apps - Intro & Learnings
 
Building Mobile Optimized Websites
Building Mobile Optimized WebsitesBuilding Mobile Optimized Websites
Building Mobile Optimized Websites
 
Basics to Search Engine Optimization & App Store Optimization with Pooja Goyal
Basics to Search Engine Optimization & App Store Optimization with Pooja GoyalBasics to Search Engine Optimization & App Store Optimization with Pooja Goyal
Basics to Search Engine Optimization & App Store Optimization with Pooja Goyal
 
How to optimize your blog for mobile traffic
How to optimize your blog for mobile trafficHow to optimize your blog for mobile traffic
How to optimize your blog for mobile traffic
 
How to create your own WordPress plugin using WP App Studio
How to create your own WordPress plugin using WP App StudioHow to create your own WordPress plugin using WP App Studio
How to create your own WordPress plugin using WP App Studio
 
PWA - Progressive Web App
PWA - Progressive Web AppPWA - Progressive Web App
PWA - Progressive Web App
 
Getting started with PhoneGap
Getting started with PhoneGapGetting started with PhoneGap
Getting started with PhoneGap
 
RESS: An Evolution of Responsive Web Design
RESS: An Evolution of Responsive Web DesignRESS: An Evolution of Responsive Web Design
RESS: An Evolution of Responsive Web Design
 
JavaScript on HP webOS: Enyo and Node.js
JavaScript on HP webOS: Enyo and Node.jsJavaScript on HP webOS: Enyo and Node.js
JavaScript on HP webOS: Enyo and Node.js
 
Progressive web apps
Progressive web appsProgressive web apps
Progressive web apps
 

Ähnlich wie Progressive Web Apps - deep dive

Basic Understanding of Progressive Web Apps
Basic Understanding of Progressive Web AppsBasic Understanding of Progressive Web Apps
Basic Understanding of Progressive Web AppsAnjaliTanpure1
 
Make your PWA feel more like an app
Make your PWA feel more like an appMake your PWA feel more like an app
Make your PWA feel more like an appÖnder Ceylan
 
Planning Your Progressive Web App
Planning Your Progressive Web AppPlanning Your Progressive Web App
Planning Your Progressive Web AppJason Grigsby
 
Progressive Web Apps 101
Progressive Web Apps 101Progressive Web Apps 101
Progressive Web Apps 101Daniel Black
 
Jws masterclass progressive web apps
Jws masterclass progressive web appsJws masterclass progressive web apps
Jws masterclass progressive web appsAlexandre Marreiros
 
Progressive Web Application by Citytech
Progressive Web Application by CitytechProgressive Web Application by Citytech
Progressive Web Application by CitytechRitwik Das
 
I/O Extended 2019 WebTech - Going big-PWA
I/O Extended 2019 WebTech - Going big-PWAI/O Extended 2019 WebTech - Going big-PWA
I/O Extended 2019 WebTech - Going big-PWAHanboramRobinJang
 
A Complete Guide To Progressive Web App.pdf
A Complete Guide To Progressive Web App.pdfA Complete Guide To Progressive Web App.pdf
A Complete Guide To Progressive Web App.pdfCerebrum Infotech
 
The web - What it has, what it lacks and where it must go - keynote at Riga D...
The web - What it has, what it lacks and where it must go - keynote at Riga D...The web - What it has, what it lacks and where it must go - keynote at Riga D...
The web - What it has, what it lacks and where it must go - keynote at Riga D...Robert Nyman
 
“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares
“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares
“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villaresrayvillares
 
Preparation Guide on Full Stack Developer.pdf
Preparation Guide on Full Stack Developer.pdfPreparation Guide on Full Stack Developer.pdf
Preparation Guide on Full Stack Developer.pdfarjunnegi34
 
PWA ( Progressive Web Apps ) - Sai Kiran Kasireddy
PWA ( Progressive Web Apps ) - Sai Kiran KasireddyPWA ( Progressive Web Apps ) - Sai Kiran Kasireddy
PWA ( Progressive Web Apps ) - Sai Kiran KasireddySai Kiran Kasireddy
 
SharePoint 2013 App Provisioning Models
SharePoint 2013 App Provisioning ModelsSharePoint 2013 App Provisioning Models
SharePoint 2013 App Provisioning ModelsShailen Sukul
 
Progressive Web App Challenges
Progressive Web App ChallengesProgressive Web App Challenges
Progressive Web App ChallengesJason Grigsby
 
7 secrets of performance oriented front end development services
7 secrets of performance oriented front end development services7 secrets of performance oriented front end development services
7 secrets of performance oriented front end development servicesKaty Slemon
 
Ecommerce Mini Project / Group Project Coding
Ecommerce Mini Project / Group Project CodingEcommerce Mini Project / Group Project Coding
Ecommerce Mini Project / Group Project CodingHemant Sarthak
 

Ähnlich wie Progressive Web Apps - deep dive (20)

Basic Understanding of Progressive Web Apps
Basic Understanding of Progressive Web AppsBasic Understanding of Progressive Web Apps
Basic Understanding of Progressive Web Apps
 
New trends on web platform
New trends on web platformNew trends on web platform
New trends on web platform
 
Progressive Web Apps
Progressive Web AppsProgressive Web Apps
Progressive Web Apps
 
Make your PWA feel more like an app
Make your PWA feel more like an appMake your PWA feel more like an app
Make your PWA feel more like an app
 
Planning Your Progressive Web App
Planning Your Progressive Web AppPlanning Your Progressive Web App
Planning Your Progressive Web App
 
Checklist for progressive web app development
Checklist for progressive web app developmentChecklist for progressive web app development
Checklist for progressive web app development
 
Progressive Web Apps 101
Progressive Web Apps 101Progressive Web Apps 101
Progressive Web Apps 101
 
Jws masterclass progressive web apps
Jws masterclass progressive web appsJws masterclass progressive web apps
Jws masterclass progressive web apps
 
Progressive Web Application by Citytech
Progressive Web Application by CitytechProgressive Web Application by Citytech
Progressive Web Application by Citytech
 
I/O Extended 2019 WebTech - Going big-PWA
I/O Extended 2019 WebTech - Going big-PWAI/O Extended 2019 WebTech - Going big-PWA
I/O Extended 2019 WebTech - Going big-PWA
 
A Complete Guide To Progressive Web App.pdf
A Complete Guide To Progressive Web App.pdfA Complete Guide To Progressive Web App.pdf
A Complete Guide To Progressive Web App.pdf
 
The web - What it has, what it lacks and where it must go - keynote at Riga D...
The web - What it has, what it lacks and where it must go - keynote at Riga D...The web - What it has, what it lacks and where it must go - keynote at Riga D...
The web - What it has, what it lacks and where it must go - keynote at Riga D...
 
Progressive Web Apps
Progressive Web AppsProgressive Web Apps
Progressive Web Apps
 
“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares
“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares
“Building Mobile Optimized Websites,” Nick Bourgeois / Ray Villares
 
Preparation Guide on Full Stack Developer.pdf
Preparation Guide on Full Stack Developer.pdfPreparation Guide on Full Stack Developer.pdf
Preparation Guide on Full Stack Developer.pdf
 
PWA ( Progressive Web Apps ) - Sai Kiran Kasireddy
PWA ( Progressive Web Apps ) - Sai Kiran KasireddyPWA ( Progressive Web Apps ) - Sai Kiran Kasireddy
PWA ( Progressive Web Apps ) - Sai Kiran Kasireddy
 
SharePoint 2013 App Provisioning Models
SharePoint 2013 App Provisioning ModelsSharePoint 2013 App Provisioning Models
SharePoint 2013 App Provisioning Models
 
Progressive Web App Challenges
Progressive Web App ChallengesProgressive Web App Challenges
Progressive Web App Challenges
 
7 secrets of performance oriented front end development services
7 secrets of performance oriented front end development services7 secrets of performance oriented front end development services
7 secrets of performance oriented front end development services
 
Ecommerce Mini Project / Group Project Coding
Ecommerce Mini Project / Group Project CodingEcommerce Mini Project / Group Project Coding
Ecommerce Mini Project / Group Project Coding
 

Mehr von Kenneth Rohde Christiansen

Mehr von Kenneth Rohde Christiansen (9)

Web Assembly (W3C TPAC presentation)
Web Assembly (W3C TPAC presentation)Web Assembly (W3C TPAC presentation)
Web Assembly (W3C TPAC presentation)
 
Generic sensors for the Web
Generic sensors for the WebGeneric sensors for the Web
Generic sensors for the Web
 
HTML literals, the JSX of the platform
HTML literals, the JSX of the platformHTML literals, the JSX of the platform
HTML literals, the JSX of the platform
 
Cold front - bridging the web and the physical world
Cold front - bridging the web and the physical worldCold front - bridging the web and the physical world
Cold front - bridging the web and the physical world
 
Web components v1 intro
Web components v1 introWeb components v1 intro
Web components v1 intro
 
WebKit, why it matters (PDF version)
WebKit, why it matters (PDF version)WebKit, why it matters (PDF version)
WebKit, why it matters (PDF version)
 
WebKit, why it matters?
WebKit, why it matters?WebKit, why it matters?
WebKit, why it matters?
 
Qt WebKit going Mobile
Qt WebKit going MobileQt WebKit going Mobile
Qt WebKit going Mobile
 
Connecting Technology for Great Experiences - How does QML and Web fit together?
Connecting Technology for Great Experiences - How does QML and Web fit together?Connecting Technology for Great Experiences - How does QML and Web fit together?
Connecting Technology for Great Experiences - How does QML and Web fit together?
 

Kürzlich hochgeladen

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...apidays
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Principled Technologies
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century educationjfdjdjcjdnsjd
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 

Kürzlich hochgeladen (20)

Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...Apidays New York 2024 - The value of a flexible API Management solution for O...
Apidays New York 2024 - The value of a flexible API Management solution for O...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
Deploy with confidence: VMware Cloud Foundation 5.1 on next gen Dell PowerEdg...
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 

Progressive Web Apps - deep dive

  • 1. PWA: Progressive Web Apps Kenneth R. Christiansen
  • 2. Hi! I am Kenneth
  • 3.
  • 4. Our team mission Move the Web Platform forward ➫ Make the web run super fast on Intel hardware ➫ Keep the open web relevant and make sure Intel has influence on the direction ➫ Align the web with Intel strategies, and take advantage of the web ➫ Identify industry trends and respond ➫ Ensure good collaboration with our partners such as Google and Apple
  • 5. Today we will talk about something that will keep the web relevant in years to come And which might make Windows 10 and Chromebooks much more relevant as well.
  • 6. ➫ Intro to PWAs, and why it matters ➫ Manifest ➫ The Service Worker ➫ Ensuring a fast load time ➫ Push notifications ➫ Background sync ➫ Web Share ➫ Sign in and credential Management Outline
  • 8. Progressive Web Apps start at the URL bar
  • 9. The idea is that any site can over time with proper engagement, can progressively turn into a more powerful and integrated experience Or people can manually opt in to that experience by installing manually from eg. a store The basic premise
  • 10. Progressive Web Apps offers the best of the modern web They work reliable, they load fast and are responsive The basic premise
  • 11. Reliable, fast loading, responsiveness
  • 12. Progressive Web Apps and often abbreviated as PWAs A community logo exists: https://medium.com/samsung-internet-dev/we-now-have-a-community-approved-progressive-web-apps-logo-823f212f57c9 The basic premise
  • 13. People the web because it is ephemeral ● Sites' resources (cache etc) gets removed when not visited regularly, depending on cache pressure ● No need to worry whether apps will update in the background even when you never use them, or just fill up your storage The basic idea
  • 14. You visit many sites a month, most never again But some you visit again and again, you engage with them The basic idea
  • 15. You can manually add sites to home screen via a menu But when you reach an engagement threshold, sites can prompt you to install them* * On Chrome, Opera, Firefox (mobile) and Samsung Internet so far The basic idea
  • 16. The added app now appears on home screen and in launcher The basic idea
  • 17. When you launch, the app starts as a separate app, indistinguible from any other native apps The basic idea
  • 19. The best of the web! Great reach, low friction safe ephemeral (deep) linkable indexable composable
  • 20. PWA are applications created with web technology, who look and act like native applications, but are being run by the build in browser. Summary
  • 21. PWAs can be installed in different ways, for instance via an app store or from the browser when visiting a site. The behavior depends on the OS and browser. Summary
  • 22. PWAs are just modern websites, no special API access, but they do get special treatment ➫ Browser chrome is configurable ➫ More integrated with host OS (optional): orientation lock, icon in launcher, no chrome ➫ Additional rights due to engagement: ○ autoplay video with sound ○ ask for persistent storage ○ more to come ➫ Some features like being a share target can only work with installed apps Summary
  • 24. { "short_name": "Flipkart", "name": "Flipkart Lite", "start_url": "/?start_url=homescreen", "display": "standalone", "orientation": "portrait", "icons": [{ "src": "icons/icon-192.png", "sizes": "192x192", "type": "image/png" }] } M A N I F E S T_ 101
  • 25. ➫ W3C working draft standard ➫ Allows defining metadata associated with a web app ➫ https://www.w3.org/TR/appmanifest/ ➫ Useful for packaging Web App Manifest
  • 26. Add site to home screen ➫ Has a unique icon and name in the launcher / home screen ➫ Can display splash-screen to the user when loading ➫ Hides the browser UI (if desired) to feel like a native app
  • 27. Describe launch style { "short_name": "SSG Portal", "name": "Intel SSG Portal", "start_url": "/?start_url=homescreen", "display": "standalone", "orientation": "portrait", ... }
  • 28. { ... "icons": [{ "src": "images/touch/icon-128x128.png", "sizes": "128x128", "type": "image/png" }, { "src": "images/touch/apple.png", "sizes": "152x152", "type": "image/png" }] } Describe your assets
  • 29. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 30. ➫ start_url and scope Entry point and URLs which are considered part of the app ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 31. ➫ start_url and scope ➫ serviceworker Service Worker associated with the app, especially for stores ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 32. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) Metadata for text and iconography ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 33. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description Info for app launcher, install dialogs ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 34. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources Icons and screens for app launcher, store ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 35. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id Store related information, like universal age rating ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 36. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation Display style (eg. fullscreen) and orientation lock ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Available values
  • 37. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color UI color like for splashscreen & app switcher ➫ related_applications and prefer_related_applications Available values
  • 38. ➫ start_url and scope ➫ serviceworker ➫ dir (direction) and lang (language) ➫ name, short_name and description ➫ icons, screenshots image resources ➫ categories and iarc_rating_id ➫ display and orientation ➫ theme_color and background_color ➫ related_applications and prefer_related_applications Refer to store apps Available values
  • 39. <link rel="manifest" href="/manifest.json"> Refer to the manifest inside your HTML resources
  • 40. Test your manifest using Chrome DevTools Chrome DevTools
  • 41. ➫ Manifest can be extended by other specs to give more functionality - check Web Share Target later ➫ The manifest entries and values are integrated in the new Web Packaging spec: ○ https://tools.ietf.org/id/draft-yasskin-dispatch-web-packaging-00.html#rfc.section.2.4 ○ https://amphtml.wordpress.com/2018/01/09/improving-urls-for-amp-pages/ ○ The parsed manifest consists of the set of signing-certificates and the manifest CBOR item. The items in manifest[“metadata”] SHOULD be interpreted as described in the [appmanifest] specification. Web App Manifest
  • 44. ➫ The Promise object is used for async calculations ➫ Represents a values which is available now, in the future or never ➫ Promise.resolve() returns a resolved promise, Promise.reject() a failed promise ➫ Much more readable code than callback hell new Promise( /* executor */ function(resolve, reject) { ... } ); Async code with promises
  • 45. pending: initial state, not fulfilled or rejected fulfilled: means that the operation is completed with success rejected: means that the operation failed Promises can be chained: The three states
  • 46. Creation and usage of promises const p3 = new Promise(function (resolve, reject) { if (/* condition */ ) { resolve(/* value */ ); // fulfilled successfully } else { reject(/* reason */ ); // error, rejected } }); function after(time) { if (typeof time !== "number" ) return Promise.reject("Not a number!" ); // static method return new Promise(resolve => { setTimeout (_ => resolve(), time); // resolve/reject can be async }); } after(1000).then(_ => console.log("hi 1 sec later" )) // an immediately resolved promise const p2 = Promise.resolve("foo"); // can get it after the fact, unlike events p2.then(res => console.log(res)); const p = new Promise(function (resolve, reject) { setTimeout (() => resolve(4), 2000); }); // handler can't change promise, just value p.then(res => { res += 2; console.log(res); }); // still gets 4 p.then(res => console.log(res)); Examples
  • 47. .then() and .catch() // Throw is the same as calling reject let p1 = new Promise((resolve, reject) => { if (true) throw new Error("rejected!"); else resolve(4); }); // A .catch() at the end catches all rejections p1.then((val) => val + 2) .then((val) => console.log("got", val)) .catch((err) => console.log("error: ", err.message)); // => error: rejected! p.then(val => console.log("fulfilled:", val), err => console.log("rejected: ", err)); // The following two gives the same result: p.then(val => console.log("fulfilled:", val)) .catch(err => console.log("rejected:", err)); p.then(val => console.log("fulfilled:", val)) .then(null, err => console.log("rejected:", err)); Examples
  • 48. ➫ Promise.all([p1, p2, ...]) -> resolves if all individual promises resolve and first at that point ➫ Promise.race([p1, p2, ...]) -> resolves when the first promise resolves Notice that .then() always returns a promise! Async with promises const p = new Promise.resolve().then(_ => console.log("hi")).then(_ => …)
  • 49. Pros ➫ Write async code in a synchronous way, without much indentation and with exception handling in one place ➫ Helps unify async APIs and wrap existing APIs with promises ➫ Guarantees that there will be no race-conditions and that future values represented by the promise are immutable (which is not the case with callbacks and events) "Cons" ➫ Promises cannot be cancelled ➫ If you don't handle their rejects/exceptions, they get swallowed ➫ Multiple .then() mixes with lots of arrow functions can be hard to read - more about async/await later Summary
  • 50. ➫ Easier way to work with promises ➫ Functions can be marked "async" and then you can "await" on functions returning promises ➫ Doesn't work top-level as you cannot mark it async Async / await
  • 51. Without and with async / await function logFetch (url) { return fetch(url) .then(response => response .text()) .then(text => { console.log(text); }).catch(err => { console.error('fetch failed' , err); }); } async function logFetch (url) { try { const response = await fetch(url); console.log(await response .text()); } catch (err) { console.log('fetch failed' , err); } } Examples More examples // wait ms milliseconds function wait(ms) { return new Promise(r => setTimeout (r, ms)); } async function hello() { await wait(500); return 'world'; } // Careful! Avoid going too sequential async function parallel () { const wait1 = wait(500); // Start a 500ms timer asynchronously… const wait2 = wait(500); // …meaning this timer happens in parallel. await wait1; // Wait 500ms for the first timer… await wait2; // …by which time this timer has already finished. return "done!"; }
  • 52. async function f() { return 1; } async means : ➫ An async function always returns a promise. ➫ If the code has return <non-promise> in it, then automatically wraps it into a resolved promise with that value. (the same happens in promise chains with .then()) // fails! let value = await f; await means : ➫ JavaScript wait until that promise settles and returns its result ➫ Doesn’t work in top level code as stated before More about async / await
  • 53. Prerequisite: fetch fetch(url).then(r => r.json()) .then(data => console.log(data)) .catch(e => console.log("Booo")) Fetch is: ➫ a massive improvement on XMLHttpRequest ➫ Support request options (e.g. CORS, headers) ➫ Can send credentials together with the request
  • 54. Proxy between web apps and the network (when available) Web Browser Service Worker Remote Server /api /api
  • 55. Service Workers are flexible! ➫ They are a specialized web worker ➫ Programmable! ➫ Choose your own caching mechanism ➫ Even different one depending on URL!
  • 56. Service Workers work on second load ➫ Progressive enhancement ➫ Site must work without ➫ Provides an update mechanism
  • 57. Registering a Service Worker if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/sw.js').then(function(registration) { // Registration was successful console.log('ServiceWorker registration successful with scope: ', registration.scope); }, function(err) { // registration failed :( console.log('ServiceWorker registration failed: ', err); }); }); }
  • 58. Install a Service Worker self.addEventListener('install', function(event) { // Perform install steps }); Inside the handler you need to: ➫ Open a cache ➫ Cache the files ➫ Confirm whether all the required assets are cached or not
  • 59. const CACHE_NAME = 'my-site-cache-v1'; const urlsToCache = [ '/', '/styles/main.css', '/script/main.js' ]; self.addEventListener('install', function(event) { // Perform install steps event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); }); Install a Service Worker
  • 62. Ideal for ➫ CSS, Images, Fonts, JS ➫ Mandatory stuff to make your site functional On install
  • 63. Ideal for ➫ Clean up and migration ➫ If you have a previous SW, good time to cleanup old caches, db… ➫ Keep the code lean On activate
  • 64. Ideal for ➫ If the whole site can't be taken offline, you may allow the user to select the content they want available offline (e.g. video, article…) ➫ Give the user “Read later”, “Save for offline” ➫ Fetch what you need and put in the cache As a result of user interaction
  • 65. Ideal for ➫ Frequently updating resources such as a user's inbox, or article contents. ➫ If a request doesn't match anything in the cache, get it from the network, send it to the page and add it to the cache at the same time. As a result of network response
  • 66. Ideal for ➫ Frequently updating resources where having the very latest version is non-essential ○ Eg. avatars can fall into this category ➫ If there's a cached version available, use it, but fetch an update for next time Stale-while-revalidate
  • 67. Ideal for ➫ Content relating to the notification ➫ Update cache here before the user clicks to provide a great offline experience As a result of a push message
  • 68. Ideal for ➫ Non-urgent updates such as social timelines or news articles. ➫ Cache when your SW is woken up by the sync event As part of background sync
  • 69. Ensuring a fast loading time
  • 70. ➫ Lots of data down the wire ➫ Multiple entries to your app (main page, deep link, embedding in social media) ➫ Not all resources are needed always (per view, per language, per log in) ➫ Many small requests are bad for performance ➫ Some resources are more expensive byte-wise (ie JS has a high parsing cost) The problem
  • 71. ➫ Optimize images - https://images.guide/ ➫ Know what libraries you use and why #usetheplatform ○ Newer libraries like preact and lit-html-(element) are quite tiny ○ Often the platform does what you need, and if not, tiny polyfills often exist ➫ Compress and tree-shake your deployment code The problem
  • 72. ➫ Push critical resources for the initial URL route ➫ Render the initial route ➫ Pre-cache remaining routes. ➫ Lazy-load and create remaining routes on demand. Focus on minimum time to interactive and maximum caching PRPL Pattern (Pillars)
  • 73. export function sayName(name) { console.log(`Hello ${name}`); } ➫ Separate code into modules ➫ Import and export symbols ➫ Support for sync and async loading ➫ Improves code organization ➫ Great for external dependencies mymodule.js import { sayName } from './mymodule.js'; sayName('Sam'); // Hello Sam app.js ES Modules
  • 74. export function sayName(name) { console.log(`Hello ${name}`); } ➫ Load on demand ➫ Good for lazy loading mymodule.js <script type="module"> async function greet() { const myModule = await import('./mymodule.js'); myModule.sayName('Sam'); } greet(); // Hello Sam </script> app.js ES Modules - dynamic loading
  • 75. ➫ ES modules work for JavaScript only ➫ You can distribute HTML and CSS as JavaScript! ○ Strings and string templates in JS bypass the JS parser (and its slowness) ○ HTML and CSS is represented as strings anyway, so not a problem ○ JSX (as used by React) is converted to function calls, so slower than text ○ New approaches like lit-html and hyperHTML use string template literals to do the same as JSX and still be as fast as HTML/CSS (except the optional JS parts) ES Modules
  • 76. Example using lit-html Great IDE support in Visual Studio Code Example of CSS and HTML distributed like JS
  • 77. How you can bundle today?
  • 78. The old way ➫ Global namespace is polluted ➫ Order of loading become important ➫ Have to make sure the main scripts are loaded before using them
  • 79. Multiple bunders exists!But it is still early days rollup.js
  • 80. ➫ Bundles code together ➫ Can hook out to other tools and analyze code to eliminate dead code ➫ Often does code-splitting into separate JS files ➫ Often requires a lot of configuration ○ Entry points, chunking etc Bundlers
  • 81. ➫ Different bundlers today allows to analyze code and do dead code elimination ➫ By providing entry points* tools can automatically split code into modules and even identify common chunks ➫ Some downsides ○ As things are up front, it is hard to adjust the splitting when things change ○ Re-chunking means throwing away code that didn't change from browser cache ➫ On the fly splitting could be better, but requires the dev to modularize the code ○ Good use-case for web components ○ Be aware with tree-shaking ○ You might tree-shake libraries and hash encode them, but components should be small and not tree-shaken *www.mysite.org vs www.mysite.org/profile etc Code splitting and tree-shaking
  • 82. ➫ There is a protocol overhead for each request compared to a single concatenated file ➫ The compression of the single large file is better than many small files ➫ Servers are slower serving many small files than a single large file Realization: Servers are faster at sending few, large files
  • 83. Server Request index.html Receive index.html Request style.css Receive style.css Request index.html Receive index.html Receive style.css Receive app.js HTTP 1.x HTTP 2.0 ➫ Server Push lets the server bundle and send assets alongside a request ○ Requires server logic ○ Allows the server to do on-demand code splitting/bundling with ES modules ○ Doesn't require everything to be distributed like JS ➫ Better caching in the browser 1 2 3 4 1 2 HTTP 2.0 Server Push Browser Browser Server
  • 84. ➫ Entrypoint needs to be very small ➫ Shell or app-shell includes the top-level app logic, router, and so on ➫ Lazily loaded fragments of the app (e.g. additional views, menus…) index.html app.js view1.js view2.js view1 dependencies shared dependencies view2 dependencies Shell Entrypoint Fragment Dependency tree
  • 85. Shell bundle Fragment bundle index.html app.js view1.js view2.js view1 dependencies shared dependencies view2 dependencies Shell Entrypoint Fragment Bundled build Fragment bundle
  • 86. ➫ Rely on CSS, HTML and ES modules ➫ Load on demand ➫ Create your own web components ➫ Share resources with hashes in names because of caches ➫ Have the server and service worker work together ➫ Do code splitting and bunding on demand ○ unbundled at received so better for caching The dream
  • 87. https://github.com/Polymer/prpl-server-node ➫ Does exactly all of this ➫ Originally written for Polymer, and HTML imports (now dead standard) ➫ Works with Service Worker and ES Modules ➫ Works as a Node server or via Cloud Functions ➫ Still not battle tested enough, gone through changes due to deprecation of HTML modules PRPL Server Node
  • 89.
  • 90. Two complementary APIs Web Push API and Notifications API
  • 91. Browser doesn’t need to be running to receive messages, thanks to Service Worker Web Push Notifications
  • 92. How does Push work?
  • 93. Get permission to send notifications Subscribe and get PushSubscription Send PushSubscription to your server Client side
  • 95. You've got a message!
  • 96. function askPermission () { return new Promise(function(resolve, reject) { const permissionResult = Notification .requestPermission (function(result) { resolve(result); }); if (permissionResult ) { permissionResult .then(resolve, reject); } }) .then(function(permissionResult ) { if (permissionResult !== 'granted') { throw new Error('We weren't granted permission.' ); } }); } Request permission
  • 97. But when to prompt?
  • 98. ➫ Avoid asking early unless necessary (chat, mail apps) ➫ Double permission pattern: Allows the user to decide without permanently blocking your site When to prompt?
  • 99. Showcase of how to do it
  • 101. function subscribeUserToPush() { return navigator.serviceWorker.register('service-worker.js') .then(function(registration) { const subscribeOptions = { userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array( 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeIHBQFLXYp5Nksh8U' ) }; return registration.pushManager.subscribe(subscribeOptions); }) .then(function(pushSubscription) { console.log('Received PushSubscription: ', JSON.stringify(pushSubscription)); return pushSubscription; }); } Subscribe to push notifications
  • 102. { "endpoint": "https://random-push-service.com/some-kind-of-unique-id-1234/v2/", "keys": { "p256dh" :"BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_Ts1XbjhazAkj7I99e8QcYP7DkM=", "auth" : "tBHItJI5svbpez7KI4CCXg==" } } Example of subscription
  • 103. const subscriptionObject = { endpoint: pushSubscription.endpoint, keys: { p256dh: pushSubscription.getKeys('p256dh'), auth: pushSubscription.getKeys('auth') } }; Send subscription to server
  • 104. function sendSubscriptionToBackEnd (subscription ) { return fetch('/api/save-subscription/' , { method: 'POST', headers: { 'Content-Type' : 'application/json' }, body: JSON.stringify(subscription ) }) .then(function(response) { if (!response.ok) { throw new Error('Bad status code from server.' ); } return response.json(); }) .then(function(responseData ) { if (!(responseData .data && responseData .data.success)) { throw new Error('Bad response from server.' ); } }); } Send subscription to server
  • 105. app.post('/api/save-subscription/' , function (req, res) { if (!isValidSaveRequest (req, res)) { return; } return saveSubscriptionToDatabase (req.body) .then(function(subscriptionId ) { res.setHeader('Content-Type' , 'application/json' ); res.send(JSON.stringify({ data: { success: true } })); }) .catch(function(err) { res.status(500); res.setHeader('Content-Type' , 'application/json' ); res.send(JSON.stringify({ error: { id: 'unable-to-save-subscription' , message: `The subscription was received but we were unable to save it to our database.` } })); }); }); On the server
  • 107. ➫ Make a POST request to a push notification service (e.g. APNS, Firebase Cloud Messaging) ➫ Use Voluntary Application Server Identification (VAPID) ➫ Encrypt the data to pass to the application ➫ Send! - Node.JS server -> NodeJS Web Push Library - Cloud functions (e.g. Firebase) Sending push notifications - Prerequisite
  • 108. const vapidKeys = { publicKey: 'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U ', privateKey: 'UUxI4O8-FbRouAevSmBQ6o18hgE4nSG3qwvJTfKc-ls ' }; webpush.setVapidDetails( 'mailto:web-push-book@gauntface.com', vapidKeys.publicKey, vapidKeys.privateKey ); Tell webpush about your app keys
  • 109. app.post('/api/trigger-push-msg/', function (req, res) { return getSubscriptionsFromDatabase() .then(function(subscriptions) { let promiseChain = Promise.resolve(); for (let i = 0; i < subscriptions.length; i++) { const subscription = subscriptions[i]; promiseChain = promiseChain.then(() => { return triggerPushMsg(subscription, dataToSend); }); } return promiseChain; }) ... // return response HTTP 500 } Trigger a push message
  • 110. const triggerPushMsg = function(subscription, dataToSend) { return webpush.sendNotification(subscription, dataToSend) .catch((err) => { if (err.statusCode === 410) { return deleteSubscriptionFromDatabase(subscription._id); } else { console.log('Subscription is no longer valid: ', err); } }); }; Trigger a push message
  • 111. Back to the client Handling of Push Events
  • 112. self.addEventListener('push', function(event) { if (event.data) { console.log('This push event has data: ', event.data.text()); } else { console.log('This push event has no data.'); } }); ➫ Browser doesn’t need to be opened, your SW will be woken up ➫ You can get the notification data with event.data.json() or event.data.text() Inside your Service Worker
  • 113. self.addEventListener('push', function(event) { const promiseChain = self.registration.showNotification('Hello, World.'); event.waitUntil(promiseChain); }); ➫ showNotification() returns a promise that resolve when notification is displayed ➫ Use waitUntil to tell the browser to keep the SW running until the promise has resolved Show your notification
  • 114. <ServiceWorkerRegistration>.showNotification(<title>, <options>); { "//": "Visual Options", "body": "<String>", "icon": "<URL String>", "image": "<URL String>", "badge": "<URL String>", "vibrate": "<Array of Integers>", "sound": "<URL String>", "dir": "<String of 'auto' | 'ltr' | 'rtl'>", ... ➫ Title is a string ➫ Options can be any of the following: Customize your notification
  • 117. self.addEventListener('notificationclick', function(event) { const clickedNotification = event.notification; clickedNotification.close(); // Do something as the result of the notification click const promiseChain = doSomething(); event.waitUntil(promiseChain); }); ➫ Notification that was clicked can be access with event.notification ➫ Remember to use waitUntil while your code is busy Handling user interactions with the notification
  • 118. const title = 'Actions Notification'; const options = { actions: [ { action: 'coffee-action', title: 'Coffee', icon: '/images/demos/action-1-128x128.png' }, { action: 'doughnut-action', title: 'Doughnut', icon: '/images/demos/action-2-128x128.png' }, ... registration.showNotification(title, options); Add notification actions
  • 119. self.addEventListener('notificationclick', function(event) { if (!event.action) { // Was a normal notification click console.log('Notification Click.'); return; } switch (event.action) { case 'coffee-action': console.log('User ❤ 's coffee.'); break; case 'doughnut-action': console.log('User ❤ 's doughnuts.'); Break; ... Handling notification actions
  • 120. self.addEventListener('notificationclose', function(event) { const dismissedNotification = event.notification; const promiseChain = notificationCloseAnalytics(); event.waitUntil(promiseChain); }); User dismiss the notification self.addEventListener('notificationclick', function(event) { const examplePage = '/demos/notification-examples/example-page.html'; const promiseChain = clients.openWindow(examplePage); event.waitUntil(promiseChain); }); Opening a window * And more at https://developers.google.com/web/fundamentals/push-notifications/common-notification-patterns Common patterns
  • 122. What is background sync? ➫ A way to not rely on having a stable internet connection ➫ A way to defer network related operations to when the connection is available ➫ Depends on Service Worker ➫ Can operate even when application is closed
  • 123. navigator.serviceWorker.ready.then(function(registration) { registration.sync.register('outbox').then(function() { // registration succeeded }, function() { // registration failed }); }); ➫ The string argument to register operates like a notification's tag. It is passed to the service worker event. Request a sync
  • 124. self.addEventListener('sync', function(event) { if (event.tag == 'outbox') { event.waitUntil(sendEverythingInTheOutbox()); } }); ➫ sync will fire when the user agent believes the user has connectivity. ➫ Use waitUntil to tell that the sync event is ongoing to keep the service worker alive if possible Respond a sync
  • 125. Sharing and caring Share data and URLs with other apps and become a share target yourself
  • 126. Web Share API ➫ Super simple API allowing to share text (a text string) and/or a URL ➫ Allows setting a title as well, but it might be ignored by the client ➫ https://wicg.github.io/web-share/
  • 127. if (navigator.share) { navigator.share({ title: 'Web Fundamentals', text: 'Check out Web Fundamentals', url: 'https://developers.google.com/web', }) .then(_ => console.log('Successful share')) .catch(err => console.log('Error:', err)); } ➫ Invokes the native share dialog so that the user can select who to share with ➫ Only work on HTTPS, following a user action (e.g. click) Using the Web Share API
  • 128. Web Share Target API ➫ Make the PWA become a share target ➫ Application has to be added by user to system ○ eg. add to homescreen / store install ➫ https://wicg.github.io/web-share-target/ ➫ Extension to Web App Manifest
  • 130. What is the sign in and credential management API? ➫ Removes friction from sign-in flows - Users can be automatically signed back ➫ Allows one tap sign in with account chooser - Users can choose an account in a native account chooser. ➫ Stores credentials - Your application can store either a username and password combination or even federated account details. These credentials can be synced across devices by the browser.
  • 131. if (navigator.credentials) { if (!user.isSignedIn()) { navigator.credentials.get({ password: true, federated: { providers: [ 'https://accounts.google.com' ] }, mediation: 'silent' }) // ... } } Sign-in users
  • 132. }).then(c => { if (c) { switch (c.type) { case 'password': return sendRequest(c); break; case 'federated': return gSignIn(c); break; } } else { return Promise.resolve(); } }) Run authentication flow
  • 133. }).then(profile => { if (profile) { updateUI(profile); } }) Update the user interface
  • 134. How to evaluate? How to know how I am performing with my PWA'ness
  • 135. Lighthouse Guiding you on the path towards progressive web app-iness. goo.gl/zzopnG
  • 136.
  • 137. Sonarwhal Linting tool for the web, built by Microsoft https://sonarwhal.com/ https://sonarwhal.com/docs/user-guide/rules/#pwas
  • 138. Browser support? Is this all Chrome and mobile only?
  • 139. Google is a big supporter ➫ Very good support on Android ➫ Working on desktop + Chrome OS support ➫ Working on extending standards and matching Electron features on desktop
  • 140. PWAs on Android ➫ Requires HTTPS, Offline experience, manifest ➫ Engagement criteria ➫ Add to homescreen dialog ➫ Installs generated Web APK from Google server
  • 141. PWAs in the Play Store? ➫ Not directly supported ➫ New Trusted Web Activity ○ Abide to Play store rules (payment etc) ○ Needs a file on server linking to app to show relationship ○ Runs in Chrome (not WebView) like Custom Tabs ○ Can be extended in Java with a onmessage/postmessage API
  • 142. Early preview of desktop support
  • 143. Early preview of desktop support
  • 144. Early preview of desktop support
  • 146. Early preview of Windows support https://mobile.twitter.com/kirupa/status/959175077836111872/video/1
  • 147. Microsoft PWA support is strategic ➫ Deeply integrated into Windows ➫ Web Assembly allows native code to run at near native speed on the web ➫ PWAs in store have access to all WinRT APIs ○ Polyfills will be available for some not-implemented APIs like Web Bluetooth
  • 148. PWAs in the Microsoft Store
  • 149. PWAs in the Microsoft Store
  • 151. ServiceWorker Cache API Push API Manifest Apple very recently started on PWA support