Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Codemotion: Progressive Web Applications (PWAs) - Jorge Ferreiro - @jgferreiro

Codemotion: Progressive Web Applications (PWAs) - Jorge Ferreiro - @jgferreiro

Technical talk for Codemotion about Progressive Web Apps (PWAs), the future of web development.

🔗 Twitter: https://twitter.com/JGFerreiro
🔗 Linkedin: https://www.linkedin.com/in/jgferreiro/

- - -

PWAs are the next revolution in web development. In this workshop, you will understand the main features of a PWA while learning how to create your own PWA in JavaScript with a real world project running React!

You will learn how to create an app with:
• Caching requests: images, CSS, index.html.
• Web Notifications
• Payments Api
• How to setup your app manifest and add to home screen
• Other PWA functionalities.

- - -

Subscribe: https://jorgeferreiro.com/newsletter

on https://www.twitter.com/jgferreiro
on https://www.linkedin.com/in/jgferreiro/
on https://www.instagram.com/jgferreiro/

Jorge Ferreiro

October 24, 2019
Tweet

More Decks by Jorge Ferreiro

Other Decks in Programming

Transcript

  1. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Our first Progressive Web App! ✅ Offline

    mode ✅ Local Notifications ✅ Cache requests ✅ Payments API ❌ Background Sync ❌ IndexedDB Emotion CSS-in-JS
  2. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Agenda • Motivation • Manifest • Service

    workers • Offline Mode • APIs and advanced topics Important quote
  3. @JGFERREIRO #CODEMOTIONPWA Web applications that adapts the user experience based

    on the device network, device capabilities and user needs Progressive Web Apps (PWAs):
  4. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA PWAs can also have native mobile apps

    cabapabilities (offline mode, push, etc.) Big selling point!
  5. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA ๏ Simplified web version ๏ Data save

    mode ๏ Limit access to advanced features Progressive enhancement: Example ๏ High quality media ๏ Advanced Features: Push, background sync, etc. United States Bad 2G connection | Cheap phone 5G connection | High quality phones % Africa
  6. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Progressive enhancement: Simplification if ('feature' in browser)

    { !// Feature is available!!! !// Do something cool with it! } else { !// Party pooper !// Browser does not support this feature !// Change your browser!!... }
  7. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Responsive ' Works offline ⚙ App-like- interactions

    Fresh Safe Discoverable Re-engageable PWA features (Alex Russell Jake Archibald) Durable Linkable Alex Russel “Progressive Web Apps: Escaping Tabs Without Losing Our Soul”
  8. @JGFERREIRO Android rocks! @JGFERREIRO #CODEMOTIONPWA ✅ Web Push ✅ Background

    Sync ✅ PWAs in the Google Play https://www.youtube.com/watch?v=7JDFjeMvxos
  9. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Smaller and 1-click install Native apps tend

    to occupy more space. Offline and notifications! Improves user retention and converstions. Adaptative experience Our apps can adapt to any device. Distribution Freedom No need apple store or play store
  10. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Our first Progressive Web App! Emotion CSS-in-JS

    ✅ Offline mode ✅ Local Notifications ✅ Cache requests ✅ Payments API ❌ Background Sync ❌ IndexedDB
  11. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Apple metatags Apple: Configuring web applications <meta

    name="apple-mobile-web-app-title" content="Pennapps"> <meta name="apple-mobile-web-app-status-bar-style" content="white"> <meta name="apple-mobile-web-app-capable" content="yes">
  12. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA More Apple metatags… icons favicon-generator.org <link rel="apple-touch-icon"

    sizes="57x57" href=“image_57_57.png"> <link rel="apple-touch-icon" sizes="60x60" href="image_60_60.png"> <link rel="apple-touch-icon" sizes="72x72" href="image_72_72.png"> <link rel="apple-touch-icon" sizes="76x76" href="image_76_76.png"> <link rel="apple-touch-icon" sizes="114x114" href="image_114_114.png"> <link rel="apple-touch-icon" sizes="120x120" href="image_120_120.png"> <link rel="apple-touch-icon" sizes="144x144" href="image_144_144.png"> <link rel="apple-touch-icon" sizes="152x152" href="image_152_152.png"> <link rel="apple-touch-icon" sizes="180x180" href="image_180_180.png">
  13. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA manifest.json is a file that tells the

    browser about your web application and how it should behave when 'installed' https://developers.google.com/web/fundamentals/web-app-manifest
  14. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Create manifest.json "short_name": "Pennapps", "name": "Pennapps agenda",

    "start_url": "/?utm_source=pwa", "display": "standalone", "theme_color": "#ffffff", "background_color": "#ffffff", "scope": "/", "icons": [] { } <link href="/static/manifest.json" rel="manifest">
  15. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA “short_name": "Pennapps", "name": "Pennapps agenda", "start_url": "/?utm_source=pwa",

    "display": "standalone", "theme_color": "#ffffff", "background_color": "#ffffff", "scope": "/", "icons": [] { } { !// 192 for the “home screen icon” "src": "/static/images/pennapps_logo_pwa_192_192.png", "sizes": "192x192", "type": "image/png" }, { !// 512 for splash screen (on Android) "src": "/static/images/pennapps_logo_pwa_512_512.png", "sizes": "512x512", "type": "image/png" } ]
  16. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Manifest.json - display fullscreen No browser UI

    ✅ Videogames standalone Hides standard browser UI elements ✅ Standalone native app minimal-ui Fullscreen display. Minimal UI elements browser Standard browser experience Google: Web App Manifest
  17. @JGFERREIRO @JGFERREIRO #codemotionpwa A service worker is like a client

    side proxy It gives you control of the cache, and how to respond to requests
  18. @JGFERREIRO @JGFERREIRO #codemotionpwa Service Worker A service worker is a

    JavaScript file that runs separately from the main browser thread
  19. SERVICE WORKER :: INSTALL CALLBACK self.addEventListener('install', (event) !=> { !//

    Install anything you need here! }) self.addEventListener('fetch', (event) !=> { console.log('I am intercepting network requests!') const url = event.request.url console.log('Requested resource url: ', url) }) Create a new SW.js file
  20. SERVICE WORKER :: REGistering new SW if ('serviceWorker' in navigator)

    { console.log('⭐ Start to register a service worker') navigator.serviceWorker.register('/sw.js') .then((registration) !=> { console.log('SW!::Registration', registration) }) .catch((error) !=> { console.log('SW!::Error registering', error) }); }
  21. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Offline mode? We need a cache! We

    need a bunch of cached resources, downloaded in the client’s browser Cached resources in the browser
  22. @JGFERREIRO @JGFERREIRO #codemotionpwa caches.open() Returns a Promise with the Cache

    object CacheStorage API https://developer.mozilla.org/en- US/docs/Web/API/CacheStorage
  23. @JGFERREIRO @JGFERREIRO #codemotionpwa Cache object Cache.add(request) Cache.addAll([request]) Cache.put(request, response) Cache.delete(request,

    options) Cache.match(request, options) Cache.matchAll(request, options) https://developer.mozilla.org/en- US/docs/Web/API/Cache (Same as fetch() + put()) Request object or a URL fetch(new Request(“/image.jpg”))
  24. CACHE API :: HELLO WORLD const cacheNameVersion = 'resources-v1' self.addEventListener('install',

    () !=> { }) caches.open(cacheNameVersion) .then((cache) !=> { cache.add("index.html") cache.add("client.bundle.js") }) .catch((error) !=> { !// Error opening the cache :/ })
  25. @JGFERREIRO @JGFERREIRO #codemotionpwa event.waitUntil() Service worker will stay in “install”

    mode, until the promise is resolved ✅ Are all assets cached? Then Service Worker is installed! ❌ Error caching critical assets? Service worker not installed.
  26. CACHE API :: REQUIRING CRITICAL ASSETs const cacheVersion = 'version-1'

    const noCriticalAssets = [‘foo.css'] const criticalAssets = ['/index.html', ‘/client.bundle.js'] function cacheAssets() { return caches.open(cacheVersion) .then((cache) !=> { cacheNoCriticalAssets(cache) return cacheCriticalAssets(cache) }) } function cacheCriticalAssets (cache) { return cache.addAll(criticalAssets) } function cacheNoCriticalAssets(cache) { cache.addAll(noCriticalAssets) } self.addEventListener('install', (event) !=> { event.waitUntil(cacheAssets()) }) This return does the magic! If failure on this promise, then waitUntil will fail
  27. CACHE API :: REMOVING CACHED ASSETS self.addEventListener('install', (event) !=> {

    !// Add assets to the service worker cache }) self.addEventListener('activate', (event) !=> { !// Remove cached assets from previous version !// using caches.delete(). }) Make sure to remove cached ASSETS!
  28. CACHE API :: Fetch image or placeholder self.addEventListener('fetch', (event) !=>

    { const acceptHeader = event.request.headers.get('accept') if (acceptHeader.includes('image')) { return event.respondWith( fetchImageOrPlaceholder(event) ) } })
  29. CACHE API :: Fetch image or placeholder function fetchImageOrPlaceholder(fetchEvent) {

    return fetch(fetchEvent.request) .then((response) !=> { if (!response.ok) { throw Error(‘Can not download from server…’) } return response }) .catch(() !=> { !// NB: Return placeholder. return caches.match(placeholderImage, { cacheName: cacheVersion }) }) } const placeholderImage = '/images/placeholder.jpg'
  30. CACHE API :: Fetch image or placeholder self.addEventListener('fetch', (event) !=>

    { const acceptHeader = event.request.headers.get('accept') if (acceptHeader.includes('image')) { return event.respondWith( fetchImageOrPlaceholder(event) ) } })
  31. CACHE API :: Fetch image or placeholder function fetchImageOrFallback(event) {

    return fetch(event.request) READ CacheStorage .then((response) !=> { if (!response.ok) { throw Error('Can not download image from server') } caches.open(cacheVersion).then(function(cache) { !// Cache in background cache.put(event.request, response) }) return response.clone() !// NB: Can't reuse responses twice: bit.ly/response-clone }) .catch(() !=> { return caches.match(fetchEvent.request).catch(function() { !// try to get cached return caches.match('/images/placeholder.jpg', { !// Return placeholder cacheName: cacheVersion }) }) }) }
  32. @JGFERREIRO Other advanced concepts Web Push Notifications using VAPID The

    App Shell Model
 (see also The PRPL Pattern) Background Sync IndexedDB
  33. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Who to follow? Jake Archibald Google @jaffathecake

    Alex Russell Chrome Team @slightlylate Sarah Clark Google @a_bowl_of_stars Pete LePage Google @petele Dominick Ng Chrome PWA @dominickng Scott Domes Indeed @scottdomes Kenneth C. Intel @kennethrohde Henrik Joreteg Consultant @HenrikJoreteg Charlie Croom Twitter @CharlieCroom Monica Dinculescu Polymer @notwaldorf
  34. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Action plan 1. Fork “pwa 101” repo

    and start it locally 2. Re-read this presentation, and open some of the links in the resources 3. Execute each of the steps to add progressive enhancement to your app
  35. @JGFERREIRO @JGFERREIRO #CODEMOTIONPWA Resources 1. Google I/O 2014 - Bridging

    the gap between the web and apps 2. How we built Twitter Lite 3. Twitter Lite and High Performance React Progressive Web Apps at Scale 4. Google workbox 5. Payment request 6. Frontend masters: Progressive web apps 7. Background sync 8. Google: Progressive web apps YouTube traiing