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

Progressive web apps are here!

Progressive web apps are here!

Progressive Web Apps use modern web capabilities to deliver an app-like user experience. They evolve from pages in browser tabs to immersive, top-level apps, maintaining the web's low friction at every moment.

They are reliable, fast, engaging and delivering amazing UX to end users. And they are here!

The slides are from my talk at http://2018.symfonycamp.org.ua/

Antonio Peric-Mazar

October 29, 2018
Tweet

More Decks by Antonio Peric-Mazar

Other Decks in Programming

Transcript

  1. Progressive Web Apps are
    here!
    Antonio Perić-Mažar, Locastic

    27.10.2018., #sfcampua

    View Slide

  2. View Slide

  3. Antonio Perić-Mažar
    CEO @ Locastic
    Co-Founder @ Blockada
    [email protected]
    @antonioperic

    View Slide

  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

    View Slide

  5. View Slide

  6. Not a Symfony talk!

    View Slide

  7. [Mobile] User Experience
    on Web

    View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. And trust me… you will never had enough cheese

    View Slide

  15. “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

    View Slide

  16. View Slide

  17. Capebility
    Reach

    View Slide

  18. “A Progressive Web App uses
    modern web capabilities to deliver
    an app-like user experience.”

    View Slide

  19. “A Progressive Web App uses
    modern web capabilities to deliver
    an app-like user experience.”

    View Slide

  20. 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.

    View Slide

  21. 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.

    View Slide

  22. View Slide

  23. Fast Integrated
    Reliable Engaging
    4
    things to focus on

    View Slide

  24. Fast Integrated
    Reliable Engaging

    View Slide

  25. Fast
    • No junky scrolling
    • No slow load performance
    • Measure and improve all the time
    • Bad connection (or no connection) is not excuse

    View Slide

  26. 53%
    of users abandon
    sites that take longer
    than 3 seconds to load

    View Slide

  27. https://cloudfour.com/thinks/ios-doesnt-support-progressive-web-apps-so-what/

    View Slide

  28. View Slide

  29. App shell model
    • Reliable performance that is consistently fast
    • Native-like interactions
    • Economical use of data

    View Slide

  30. Fast Integrated
    Reliable Engaging

    View Slide

  31. 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

    View Slide

  32. https://www.mobigyaan.com/android-8-0-oreo-vs-ios-11-which-is-better

    View Slide

  33. View Slide

  34. View Slide

  35. https://techcrunch.com/2017/08/25/majority-of-u-s-consumers-still-download-zero-apps-per-month-says-comscore/

    View Slide

  36. https://techcrunch.com/2017/08/25/majority-of-u-s-consumers-still-download-zero-apps-per-month-says-comscore/

    View Slide

  37. https://www.technology.org/2017/07/28/progressive-web-apps-vs-native-which-is-better-for-your-business/

    View Slide

  38. 80%
    users intentionally moved apps
    to their home screen

    View Slide

  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

    View Slide

  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/

    View Slide

  41. {
    "background_color":"#ffffff",
    "description":"It's what's happening. From breaking news and entertainment, sports
    and politics, to big events and everyday interests.",
    "display":"standalone",
    "gcm_sender_id":"49625052041",
    "gcm_user_visible_only":true,
    "icons":[
    {
    "src":"https://abs.twimg.com/responsive-web/web/ltr/icon-default.
    604e2486a34a2f6e.png",
    "sizes":"192x192",
    "type":"image/png"
    },
    {
    "src":"https://abs.twimg.com/responsive-web/web/ltr/icon-default.
    604e2486a34a2f6e.png",
    "sizes":"512x512",
    "type":"image/png"
    }
    ],
    "name":"Twitter",
    "share_target":{
    "action":"compose/tweet",
    "params":{
    "title":"title",
    "text":"text",
    "url":"url"
    }
    },
    "short_name":"Twitter",
    "start_url":"/",
    "theme_color":"#ffffff",
    “scope":"/"
    }

    View Slide

  42. View Slide

  43. {
    "background_color":"#ffffff",
    "display":"standalone",
    "icons":[

    ],
    "name":"Twitter",
    "short_name":"Twitter",
    "start_url":"/",
    "theme_color":"#ffffff",
    “scope":"/"
    }

    You can add it now to 

    your app

    View Slide

  44. What are the criteria?
    • The web app is not already installed
    • Meets a user engagement heuristic (currently, the user
    has interacted with the domain for at least 30 seconds)
    • Served over HTTPS (required for service workers)
    • Has registered a service worker with a fetch event
    handler

    View Slide

  45. What are the criteria?
    • Includes a web app manifest that includes:
    • Short name or name
    • Icons must include a 192px and a 512px sized icons
    • start_url
    • Display must be: fullscreen, standalone, or minimal-
    ui

    View Slide

  46. What are the criteria?
    • When these criteria are met, Chrome will fire a
    beforeinstallprompt event that you can use to
    prompt the user to install your Progressive Web App.
    let deferredPrompt;
    window.addEventListener('beforeinstallprompt', (e) => {
    // Prevent Chrome 67 and earlier from automatically showing the prompt
    e.preventDefault();
    // Stash the event so it can be triggered later.
    deferredPrompt = e;
    });

    View Slide

  47. What are the criteria?
    btnAdd.addEventListener('click', (e) => {
    // hide our user interface that shows our A2HS button
    btnAdd.style.display = 'none';
    // Show the prompt
    deferredPrompt.prompt();
    // Wait for the user to respond to the prompt
    deferredPrompt.userChoice
    .then((choiceResult) => {
    if (choiceResult.outcome === 'accepted') {
    console.log('User accepted the A2HS prompt');
    } else {
    console.log('User dismissed the A2HS prompt');
    }
    deferredPrompt = null;
    });
    });

    View Slide

  48. https://ponyfoo.com/articles/progressive-app-serviceworker

    View Slide

  49. 40%
    higher interaction rate from
    Home screen

    View Slide

  50. View Slide

  51. Web Payment API!

    View Slide

  52. 66%
    of purchases on mobile are
    on the web

    View Slide

  53. 1/3
    of purchases on Web are
    via mobile
    That means the UX

    is BROKEN!

    View Slide

  54. Checkout forms today:
    • Manual
    • Tedious
    • Slow
    • N-taps
    http://www.alyssatucker.com/improving-hollars-ios-checkout-process/

    View Slide

  55. Autofill - step forward
    • Autocomplete attributes
    • 30% faster
    • Automatic
    • Simple
    • Slow
    • n-taps
    http://www.alyssatucker.com/improving-hollars-ios-checkout-process/

    View Slide

  56. Web Payment API!

    View Slide

  57. View Slide

  58. View Slide

  59. // Supported payment methods
    const paymentMethods = [{
    supportedMethods: 'basic-card',
    data: {
    supportedNetworks: [
    'visa', 'mastercard', 'amex', 'discover',
    'diners', 'jcb', 'unionpay'
    ]
    }
    }, {
    supportedMethods: 'https://bobpay.xyz/pay',
    }];
    Define payment methods

    View Slide

  60. var options = {
    requestShipping: true,
    requestPayerEmail: true,
    requestPayerPhone: true,
    requestPayerName: true,
    shippingType: 'delivery'
    };
    var request = new PaymentRequest(paymentMethods, paymentDetails,
    paymentOptions);
    Setup your payment options

    View Slide

  61. request.show().then(response => {
    // [process payment]
    // send to a PSP etc.
    response.complete('success');
    });
    Show payment screen

    View Slide

  62. View Slide

  63. { // example response

    "methodName": "basic-card",

    "details": {

    "cardholderName": "Larry Page",

    "cardNumber": "4111111111111111",

    "expiryMonth": "12",

    "expiryYear": "2020",

    "cardSecurityCode": "111",

    "billingAddress": { ... }

    },

    "payerName": "Larry Page",

    "payerPhone": "212-555-1212",

    "payerEmail": "[email protected]"

    }

    Payment response

    View Slide

  64. Web Payment API!
    • Automatic
    • Simple
    • Fast
    • 1-tap
    • Supportes payment gatway,

    or some applications payment 

    (Google Pay)
    https://paymentrequest.show/images/pr-woocommerce.gif

    View Slide

  65. More APIs
    • Media Session
    • Media Capture API
    • Casting support
    • Web bluetooth
    • Web Share

    View Slide

  66. More APIs
    • Media Session
    • Media Capture API
    • Casting support
    • Web bluetooth
    • Web Share

    View Slide

  67. Remember
    users expect to be able to
    interact with your app in the
    same way that they do all of
    the other apps on their device

    View Slide

  68. Fast Integrated
    Reliable Engaging

    View Slide

  69. Reliable
    Reliability means, never showing the Downsaur

    View Slide

  70. View Slide

  71. 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.

    View Slide

  72. 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

    View Slide

  73. Service Workers

    View Slide

  74. Service Workers

    View Slide

  75. Service Workers
    Service Workers

    View Slide

  76. Service Workers
    • Rich offline experiences
    • Background syncs
    • Push notifications
    • …

    View Slide

  77. 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.

    View Slide

  78. 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

    View Slide

  79. Service Workers lifecycle

    View Slide

  80. 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);
    });
    });
    }

    View Slide

  81. View Slide

  82. On Install
    var CACHE_NAME = 'my-site-cache-v1';
    var 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);
    })
    );
    });

    View Slide

  83. View Slide

  84. Cache and return requests
    self.addEventListener('fetch', function(event) {
    event.respondWith(
    caches.match(event.request)
    .then(function(response) {
    // Cache hit - return response
    if (response) {
    return response;
    }
    return fetch(event.request);
    }
    )
    );
    });

    View Slide

  85. View Slide

  86. 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

    View Slide

  87. 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.

    View Slide

  88. Update Service Worker
    • self.skipWaiting()
    • Skips waiting for refresh to start using new SW

    View Slide

  89. On User Interaction

    View Slide

  90. // 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);
    });
    });
    });

    View Slide

  91. On Network response

    View Slide

  92. self.addEventListener('fetch', function(event) {
    event.respondWith(
    caches.open('mysite-dynamic').then(function(cache) {
    return cache.match(event.request).then(function (response) {
    return response || fetch(event.request).then(function(response) {
    cache.put(event.request, response.clone());
    return response;
    });
    });
    })
    );
    });

    View Slide

  93. On Background Sync

    View Slide

  94. self.addEventListener('sync', function(event) {
    if (event.id == 'update-leaderboard') {
    event.waitUntil(
    caches.open('mygame-dynamic').then(function(cache) {
    return cache.add('/leaderboard.json');
    })
    );
    }
    });

    View Slide

  95. 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
    • ServiceWorker-side templating

    View Slide

  96. Cache only

    View Slide

  97. Cache only
    self.addEventListener('fetch', function(event) {
    // If a match isn't found in the cache, the response
    // will look like a connection error
    event.respondWith(caches.match(event.request));
    });

    View Slide

  98. Network only

    View Slide

  99. Network only
    self.addEventListener('fetch', function(event) {
    event.respondWith(fetch(event.request));
    // or simply don't call event.respondWith, which
    // will result in default browser behaviour
    });

    View Slide

  100. Cache, falling back to network

    View Slide

  101. Cache, falling back to network
    self.addEventListener('fetch', function(event) {
    event.respondWith(
    caches.match(event.request).then(function(response) {
    return response || fetch(event.request);
    })
    );
    });

    View Slide

  102. Network, falling back to Cache

    View Slide

  103. Network, falling back to Cache
    self.addEventListener('fetch', function(event) {
    event.respondWith(
    fetch(event.request).catch(function() {
    return caches.match(event.request);
    })
    );
    });

    View Slide

  104. Cache, than Network

    View Slide

  105. Cache, than Network
    var networkDataReceived = false;
    startSpinner();
    // fetch fresh data
    var networkUpdate = fetch('/data.json').then(function(response) {
    return response.json();
    }).then(function(data) {
    networkDataReceived = true;
    updatePage(data);
    });
    // fetch cached data
    caches.match('/data.json').then(function(response) {
    if (!response) throw Error("No data");
    return response.json();
    }).then(function(data) {
    // don't overwrite newer network data
    if (!networkDataReceived) {
    updatePage(data);
    }
    }).catch(function() {
    // we didn't get cached data, the network is our last hope:
    return networkUpdate;
    }).catch(showErrorMessage).then(stopSpinner);

    View Slide

  106. Cache, than Network
    self.addEventListener('fetch', function(event) {
    event.respondWith(
    caches.open('mysite-dynamic').then(function(cache) {
    return fetch(event.request).then(function(response) {
    cache.put(event.request, response.clone());
    return response;
    });
    })
    );
    });

    View Slide

  107. View Slide

  108. View Slide

  109. View Slide

  110. 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

    View Slide

  111. Your goal is to provide a good
    experience that lessens the
    impact of changes in
    connectivity

    View Slide

  112. Fast Integrated
    Reliable Engaging

    View Slide

  113. 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

    View Slide

  114. Engaging

    View Slide

  115. What makes good notification
    Push. Push. Back upon now. (Courtesy Enrique Iglesias)

    View Slide

  116. What makes good notification
    • Timely - I feel I need and it matters now
    • Precise - specific info, what happens
    • Personal - make it personal

    View Slide

  117. What makes good notification

    View Slide

  118. https://www.slideshare.net/SeulgiChoi4/pwa-push-notification

    View Slide

  119. https://www.slideshare.net/SeulgiChoi4/pwa-push-notification

    View Slide

  120. View Slide

  121. 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/');
    }
    });

    View Slide

  122. 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" }
    ]
    }

    View Slide

  123. 43%
    agrees to an app’s request to
    allow push notifications

    View Slide

  124. Credentials API!
    • Removes friction from sign-in flows - Users can be
    automatically signed back into a site even if their session has
    expired or they saved credentials on another device.
    • 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.

    View Slide

  125. View Slide

  126. View Slide

  127. Tools!

    View Slide

  128. Lighthouse

    View Slide

  129. View Slide

  130. View Slide

  131. Some show case!

    View Slide

  132. 65% increase in page per session
    75% increase in Tweets sent

    20% decrease in bounce rate
    Twitter Lite

    View Slide

  133. 76% higher conversation across browsers
    4x higher interaction rate from Add to screen
    Increased usage of native apps also
    Alibaba

    View Slide

  134. 80%+ conversation
    54% smaller than Android app
    120% smaller than iOS app
    BookMyShow

    View Slide

  135. 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

    View Slide

  136. Myths about PWA!

    View Slide

  137. PWAs are only for
    offline apps

    View Slide

  138. PWAs are a mobile thing

    View Slide

  139. PWAs are a Google-only
    thing

    View Slide

  140. View Slide

  141. PWAs are not ready yet

    View Slide

  142. View Slide

  143. View Slide

  144. View Slide

  145. View Slide

  146. https://pwa.rocks/

    View Slide

  147. View Slide

  148. View Slide

  149. Don’t be driven with hype,
    choose the best fit for your
    project

    View Slide

  150. It is not about PWA vs Native
    apps, it is about Users

    View Slide

  151. Thank you!

    View Slide

  152. QnA?

    View Slide