This document discusses progressive web apps (PWAs) and how to make them fast, integrated, reliable, and engaging. It focuses on four key areas: fast performance by optimizing load times and working offline; integrated user experience by making the app feel like a native app; reliable functionality even on poor network connections using service workers; and engaging design with features like push notifications. The document provides examples of how to implement service workers, push notifications, and other technologies to build PWAs that meet these criteria.
4. Locastic
• We help clients create amazing web and mobile apps (since 2011)
• mobile development
• web development
• UX/UI
• Training and Consulting
• Shift Conference, Symfony Croatia
• www.locastic.com t: @locastic
17. “I don't care how many kick-ass Visio architecture
diagrams you have; as far as the user is concerned,
the UI is the application. I know UI US HARD, but you
have to build an impressive UI if you want to be taken
seriously. Give your UI the high priority it deserves.”
Jeff Atwood, Coding Horror
blog
20. “A Progressive Web App uses
modern web capabilities to deliver
an app-like user experience.”
21. “A Progressive Web App uses
modern web capabilities to deliver
an app-like user experience.”
22. PWA is:
• Progressive - Works for every user, regardless of browser choice because
it's built with progressive enhancement as a core tenet.
• Responsive - Fits any form factor: desktop, mobile, tablet, or whatever is
next.
• Connectivity independent - Enhanced with service workers to work
offline or on low-quality networks.
• App-like - Feels like an app, because the app shell model separates the
application functionality from application content .
• Fresh - Always up-to-date thanks to the service worker update process.
23. PWA is:
• Safe - Served via HTTPS to prevent snooping and to ensure content hasn't
been tampered with.
• Discoverable - Is identifiable as an "application" thanks to W3C manifest
and service worker registration scope, allowing search engines to find it.
• Re-engageable - Makes re-engagement easy through features like push
notifications.
• Installable - Allows users to add apps they find most useful to their home
screen without the hassle of an app store.
• Linkable - Easily share the application via URL, does not require complex
installation.
33. Integrated
• User should not reach browser to reach your app
• They should be able to interact same as with any
other app on their device
• They expect to have all possibilities as other apps
• Users should be able to start app from their home
screen
39. Broken experience
• Required user interaction
• Where it will start?
• Would it work offline?
https://medium.com/@saigeleslie/how-to-create-a-progressive-web-app-with-react-in-5-mins-or-less-3aae3fe98902
40. Web manifest
• Simple JSON file
• Tell browsers about your app and how it should behave
once app is ‘installed’
• Having manifest is required to show add to home screen
pop-up
• Works for desktop and mobile apps (chrome)
• https://manifest-validator.appspot.com/
• https://app-manifest.firebaseapp.com/
61. Reliable
• The quality of a network connection can be affected by a number of factors such as:
• Poor coverage of a provider.
• Extreme weather conditions.
• Power outages.
• Users travelling into “dead zones” such as buildings that block their network
connections.
• Travelling on a train and going through a tunnel.
• Internet connection is managed by a third party and time boxed when it will be
active or inactive like in an airport or hotel.
• Cultural practises that require limited or no internet access at specific times or
days.
62. Reliable
• We need instant loading offline
• 60% of mobile connection is 2G
• Fast Application is UX
• 14 sec to load average website on 4g
• 19 sec to load average website on 3G
67. Service Workers
• Script that browser runs in background, separated
from web page
• It is Javascript worker, so it cannot access to DOM
directly
• Service worker is a programmable network proxy,
allowing you to control how network requests from
your page are handled.
68. Service Workers
• It's terminated when not in use, and restarted when
it's next needed, so you cannot rely on global state
within a service worker's onfetch and
onmessage handlers.
• Service workers make extensive use of promises
• Service worker is for second load
70. Register 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);
});
});
}
71.
72. Service workers Events
• On install - as a dependency
• On install - not as a dependency
• On activate
• On user interaction
• On network response
• Stale-while-revalidate
• On push message
• On background-sync
76. On install - not as a dependency
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mygame-core-v1').then(function(cache) {
cache.addAll(
// levels 11-20
);
return cache.addAll(
// core assets & levels 1-10
);
})
);
});
77. Update Service Worker
• Update your service worker JavaScript file. When the user navigates to your
site, the browser tries to redownload the script file that defined the service
worker in the background. If there is even a byte's difference in the service
worker file compared to what it currently has, it considers it new.
• Your new service worker will be started and the install event will be fired.
• At this point the old service worker is still controlling the current pages so the
new service worker will enter a waiting state.
• When the currently open pages of your site are closed, the old service
worker will be killed and the new service worker will take control.
• Once your new service worker takes control, its activate event will be
fired.
82. // on user interaction
document.querySelector('.cache-article').addEventListener('click',
function(event) {
event.preventDefault();
var id = this.dataset.articleId;
caches.open('mysite-article-' + id).then(function(cache) {
fetch('/get-article-urls?id=' + id).then(function(response) {
// /get-article-urls returns a JSON-encoded array of
// resource URLs that a given article depends on
return response.json();
}).then(function(urls) {
cache.addAll(urls);
});
});
});
89. SW: Serving suggestions - responding to
requests
• Cache only
• Network only
• Cache, falling back to network
• Cache & network race
• Network falling back to cache
• Cache then network
• Generic fallback
97. Cache & network race// Promise.race is no good to us because it rejects if
// a promise rejects before fulfilling. Let's make a proper
// race function:
function promiseAny(promises) {
return new Promise((resolve, reject) => {
// make sure promises are all promises
promises = promises.map(p => Promise.resolve(p));
// resolve this promise as soon as one resolves
promises.forEach(p => p.then(resolve));
// reject if all promises reject
promises.reduce((a, b) => a.catch(() => b))
.catch(() => reject(Error("All failed")));
});
};
self.addEventListener('fetch', function(event) {
event.respondWith(
promiseAny([
caches.match(event.request),
fetch(event.request)
])
104. Generic fallback
self.addEventListener('fetch', function(event) {
event.respondWith(
// Try the cache
caches.match(event.request).then(function(response) {
// Fall back to network
return response || fetch(event.request);
}).catch(function() {
// If both fail, show a generic fallback:
return caches.match('/offline.html');
// However, in reality you'd have many different
// fallbacks, depending on URL & headers.
// Eg, a fallback silhouette image for avatars.
})
);
});
105.
106.
107.
108. Reliable conclusion
• Think how you design for the success, failure and instability of
a network connection
• Data may be expensive, so be considerate to the user
• Make sure performance is part of your design process and UX
• Try to provide offline by default if your app doesn't require
much data
• Inform users of their current state and of changes in states
• https://serviceworke.rs/ - different examples
112. Engaging
• Charming and Attractive
• Shift way how we think in patterns and designs
from web patterns to some native patterns
• Push notifications (browser doesn’t need to be
opened)
• Push Notification API
120. self.addEventListener('push', function(event) {
if (event.data.text() == 'new-email') {
event.waitUntil(
caches.open('mysite-dynamic').then(function(cache) {
return fetch('/inbox.json').then(function(response) {
cache.put('/inbox.json', response.clone());
return response.json();
});
}).then(function(emails) {
registration.showNotification("New email", {
body: "From " + emails[0].from.name
tag: "new-email"
});
})
);
}
});
self.addEventListener('notificationclick', function(event) {
if (event.notification.tag == 'new-email') {
// Assume that all of the resources needed to render
// /inbox/ have previously been cached, e.g. as part
// of the install handler.
new WindowClient('/inbox/');
}
});
121. Push Notifications
{
"body": "Did you make a $1,000,000 purchase at Dr. Evil...",
"icon": "images/ccard.png",
"vibrate": [200, 100, 200, 100, 200, 100, 400],
"tag": "request",
"actions": [
{ "action": "yes", "title": "Yes", "icon": "images/yes.png" },
{ "action": "no", "title": "No", "icon": "images/no.png" }
]
}
132. Cut load times from 11.91 to 4.69
seconds
90% smaller than Native Android
App
https://medium.com/@addyosmani/a-tinder-progressive-web-app-
performance-case-study-78919d98ece0
Tinder