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

DevIT; Thessaloniki; Progressive Web Apps: Future of web development

DevIT; Thessaloniki; Progressive Web Apps: Future of web development

Slides, from the presentation performed on the DevIT conference in Thessaloniki.

Containing overview of what PWAs are, how to start working with them using ngsw (Angular solution) and/or workbox. Refers also to tools like pwabuilder.com and serwiceworke.rs

Maciej Treder

June 03, 2019
Tweet

More Decks by Maciej Treder

Other Decks in Technology

Transcript

  1. @maciejtreder

    View Slide

  2. @maciejtreder
    • Kraków, Poland
    • Over 10 years of experience in IT,
    • Senior Software Development Engineer at Akamai Technologies,
    • Articles author
    • Open Source contributor (founder of @ng-toolkit)

    View Slide

  3. • Cambridge, Massachusetts
    • Content Delivery Network
    • Over 240 00 servers deployed in more then 120 countries
    • Serves 15%-30% of the Internet traffic

    View Slide

  4. Progressive Web Applications
    Future of web development

    View Slide

  5. ARPANET
    • 1969 first package sent

    View Slide

  6. HTTP
    • 1969 first website launch

    View Slide

  7. HTML
    • 1993 initial release
    • 1994 Netscape Navigator
    • 1995 Internet Explorer

    View Slide

  8. 1995: LAMP & JavaScript
    • Linux
    • Apache
    • MySQL
    • PHP

    View Slide

  9. Cascading Style Sheets
    • Introduced in 1996

    View Slide

  10. In the meantime…

    View Slide

  11. 1999
    • Initial release of Wireless Application Protocol
    • Asynchronous JavaScript and XML (AJAX) appears

    View Slide

  12. RWD
    • 2002 - first draft of the CSS 2

    View Slide

  13. Single Page App
    • Everything on one page
    • Content loaded asynchronously (AJAX calls)
    • No ‘reload’
    • Share-able links (# - strategy, later on HTML5 history API)
    Native-like experience

    View Slide

  14. ! Reliable
    ! Engaging
    ! Fast
    Progressive Web App

    View Slide

  15. Site is served over HTTPS
    Pages are responsive on tablets & mobile devices
    Site works cross-browser
    Page transitions don't feel like they block on the network
    Each page has a URL
    First load fast even on 3G
    All app URLs load while offline
    Metadata provided for Add to Home screen
    PWA checklist

    View Slide

  16. Service Worker

    View Slide

  17. JavaScript Lifecycle
    let tick = 0;
    setInterval(() => console.log(tick++), 1000);
    0, 1, 2, 3, 4 0, 1, 2, 3, 4 0, 1, 2, 3, 4

    View Slide

  18. Service Worker
    • Executed in separate thread
    • Persistent background processing
    • Enabling new features

    View Slide

  19. ServiceWorker Lifecycle
    let tick = 0;
    setInterval(() => console.log(tick++), 1000);
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
    if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js');
    });
    }
    service-worker.js
    index.html
    , 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

    View Slide

  20. How to start?
    https://developers.google.com/web/tools/workbox/
    ng add @angular/pwa
    home-grown

    View Slide

  21. ng add @angular/pwa
    • ngsw-config.json
    • manifest.json

    View Slide

  22. ngsw-config.json
    • App information
    • What to cache
    • How to cache
    {
    “index”: “/index.html”,
    “appData”: { “name”: “app name”, “description”: “app description”},
    “ ”: [{}],
    “ “: [{}]
    }
    assetGroups
    dataGroups

    View Slide

  23. assetGroups
    • external & internal parts of application
    {
    “assetGroups”: [{
    “name”: “images_and_fonts”,
    “installMode”: “lazy”,
    “updateMode”: “prefetch”,
    “resources”: {
    “files”: [“/assets/img/**”],
    “urls”: [“https://fonts.googleapis.com/**"]
    }
    }]
    }

    View Slide

  24. ngsw-config.json
    • What to cache
    • How updates should be performed
    {
    “index”: “/index.html”,
    “appData”: { “name”: “app name”, “description”: “app description”},
    “ ”: [{}],
    “ “: [{}]
    }
    assetGroups
    dataGroups

    View Slide

  25. dataGroups
    • API calls
    {
    “dataGroups”: [{
    “name”: “api_calls”,
    “urls”: [“https://my-app.com/api/**”],
    “cacheConfig”: {
    “maxSize”: 10,
    “maxAge”: “1d”,
    “timeout”: “4s”,
    “strategy”: “freshness”
    }
    }]
    }

    View Slide

  26. How to start?
    https://developers.google.com/web/tools/workbox/
    ng add @angular/pwa
    home-grown

    View Slide

  27. Workbox
    importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
    if (workbox) {
    console.log(`Yay! Workbox is loaded `);
    } else {
    console.log(`Boo! Workbox didn't load `);
    }
    <br/>if ('serviceWorker' in navigator) {<br/>window.addEventListener('load', () => {<br/>navigator.serviceWorker.register('/service-worker.js');<br/>});<br/>}<br/>
    service-worker.js
    index.html

    View Slide

  28. Workbox-CLI
    importScripts('https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js');
    if (workbox) {
    workbox.precaching.precacheAndRoute([]);
    } else {
    console.log(`Boo! Workbox didn't load `);
    }
    www/service-worker.js -> sw-dev.js
    npm install workbox-cli —-global
    workbox wizard

    View Slide

  29. Workbox-CLI
    module.exports = {
    "globDirectory": "www/",
    "globPatterns": [
    "**/*.{html,js}"
    ],
    "swDest": "www/service-worker.js",
    "swSrc": "sw-dev.js"
    };
    workbox-config.js (created by workbox wizard)
    > workbox injectManifest
    Using configuration from /Users/mtreder/something/workbox-config.js.
    The service worker was written to www/service-worker.js
    2 files will be precached, totalling 808 B.

    View Slide

  30. Caching
    workbox.precaching.precacheAndRoute([
    {
    "url": "index.html",
    "revision": "40f4848158e6e82701c4e9904c981449"
    },
    {
    "url": "script.js",
    "revision": "85655e0fbf9a9093747877ee5270618e"
    }
    ]);
    workbox.precaching.precacheAndRoute([]);
    workbox injectManifest

    View Slide

  31. Requests caching
    cache first network first
    network only cache only

    View Slide

  32. workbox.routing.registerRoute(
    new RegExp('/images/avatars/'),
    new workbox.strategies.StaleWhileRevalidate()
    );
    workbox.routing.registerRoute(
    new RegExp('/styles/'),
    new workbox.strategies.CacheFirst()
    );
    Requests caching

    View Slide

  33. workbox.routing.registerRoute(
    new RegExp('/admin/'),
    new workbox.strategies.NetworkOnly()
    );
    workbox.routing.registerRoute(
    new RegExp('/app/v2/'),
    new workbox.strategies.CacheOnly()
    );
    Requests caching

    View Slide

  34. Service Worker
    ! Content caching
    ! Push notifications
    ! Background synchronization

    View Slide

  35. Push notifications
    your server push service

    View Slide

  36. Obtain Keys
    https://web-push-codelab.glitch.me

    View Slide

  37. Use PushManager API
    Use importScripts section in your service-worker dev version
    importScripts: ['push-notifications.abcd1234.js']
    https://developer.mozilla.org/en-US/docs/Web/API/Push_API

    View Slide

  38. https://serviceworke.rs

    View Slide

  39. import { SwPush } from '@angular/service-worker';
    export class PushComponent implements OnInit {
    constructor(private swPush: SwPush) {}
    public ngOnInit(): void {
    this.swPush.requestSubscription({serverPublicKey: ‘key_obtained_by_push_companion'})
    .then((pushSubscription: ) => {
    // save key on the server
    });
    }
    }
    Register client
    PushSubscription

    View Slide

  40. interface PushSubscription {
    readonly expirationTime: number | null;
    readonly options: PushSubscriptionOptions;
    getKey(name: PushEncryptionKeyName): ArrayBuffer | null;
    toJSON(): PushSubscriptionJSON;
    unsubscribe(): Promise;
    }
    PushSubscription
    readonly endpoint: string;

    View Slide

  41. Engage Your Customers
    {
    title: “my notification”,
    content: “content”
    }
    https://push-service.com/
    subscription_endpoint
    https://push-service.com/
    subscription_endpoint
    your server
    push service

    View Slide

  42. Engage Your Customers
    • https://github.com/web-push-libs/webpush-java

    Pure Java client
    • https://github.com/maciejtreder/aws-sns-webpush

    AWS Lambda + AWS SNS

    View Slide

  43. Service Worker
    ! Content caching
    ! Push notifications
    ! Background synchronization

    View Slide

  44. Background synchronization
    -Fi
    Wi

    View Slide

  45. Background synchronization
    Workbox Background Sync
    Home-grown solution with the HttpInterceptor

    View Slide

  46. Background synchronization
    const bgSyncPlugin = new workbox.backgroundSync.Plugin('myQueueName', {
    maxRetentionTime: 24 * 60 // Retry for max of 24 Hours
    });
    workbox.routing.registerRoute(
    /\/api\/.*\/*.json/,
    workbox.strategies.networkOnly({
    plugins: [bgSyncPlugin]
    }),
    'POST'
    );

    View Slide

  47. Service Worker
    !
    ! Push notifications
    ! Background synchronization
    Content caching

    View Slide

  48. ng add @angular/pwa
    • ngsw-config.json
    • manifest.json

    View Slide

  49. manifest.json
    {
    "name": "Akamai Affinity",
    "short_name": "Affinity",
    "theme_color": "#f08b00",
    "background_color": "#363636",
    "display": "standalone",
    "scope": "/",
    "start_url": "/",
    "icons": [
    {
    "src": "/assets/images/icons/favicon-32.png",
    "sizes": "32x32",
    "type": "image/png"
    }
    ]
    }

    View Slide

  50. PWABuilder.com

    View Slide

  51. • Server-Side Rendering
    • “Non-updatable” application
    Pitfalls

    View Slide

  52. Server-Side Rendering
    GET / GET /anotherPage

    View Slide

  53. Server-Side Rendering
    GET /
    GET /anotherPage

    View Slide

  54. Server-Side Rendering
    • Problem: 

    Lack of the service-worker (navigator) in the NodeJS environment
    • Solutions:
    • Provide mock of ServiceWorkerModule in the server entry module
    • ng add @ng-toolkit/pwa

    View Slide

  55. Pitfalls
    • Server-Side Rendering
    • “Non-updatable” application

    View Slide

  56. “Non-updatable” application
    GET /
    GET / API calls

    View Slide

  57. “Non-updatable” application
    • Problem: 

    Once installed app is “never” updated
    • Solutions:
    • Implement update mechanism using SwUpdate service
    • Use workbox-window
    SwUpdate

    View Slide

  58. SwUpdate
    • @angular/service-worker
    • isEnabled
    • available - emits an event when new version of an app is available
    • checkForUpdate() - indicates check for update & updates application

    View Slide

  59. SwUpdate
    public ngOnInit(): void {
    if (!isPlatformBrowser(this.platformId)) {
    return;
    }
    if (this.swUpdate.isEnabled) {
    this.swUpdate.available.subscribe((evt) => {
    setTimeout(() => {this.windowRef.nativeWindow.location.reload(true); }, 1);
    });
    this.swUpdate.checkForUpdate().then(() => {
    // noop
    }).catch((err) => {
    console.error('error when checking for update', err);
    });
    }
    }

    View Slide

  60. workbox-window
    import { Workbox } from 'workbox-window';
    if ('serviceWorker' in navigator) {
    const wb = new Workbox('service-worker.js');
    wb.addEventListener('installed', event => {
    if (event.isUpdate) {
    if (confirm(`New content is available!. Click OK to refresh`)) {
    window.location.reload();
    }
    }
    });
    }

    View Slide

  61. Tools

    View Slide

  62. View Slide

  63. View Slide

  64. Browser support
    85%

    View Slide

  65. Safari Push
    • Apple developer membership required
    • Works only on Safari Desktop (lack of iOS support)
    • Written tutorial: https://apple.co/2A80fB4
    • Video tutorial: https://apple.co/2S11wkJ

    View Slide

  66. Add to desktop (iOS)

    View Slide

  67. Add to desktop (iOS)

    View Slide

  68. Add to desktop (iOS)








    View Slide

  69. PWACompat
    • https://github.com/GoogleChromeLabs/pwacompat
    • Analyze manifest.json
    • Brings necessary html tags ‘on the fly’ (like splash screen for mobile safari
    or pinned sites features for IE/Edge)

    integrity="sha384-uONtBTCBzHKF84F6XvyC8S0gL8HTkAPeCyBNvfLfsqHh+Kd6s/kaS4BdmNQ5ktp1"
    crossorigin="anonymous">

    View Slide

  70. Where we are?
    Offline capabilities
    Push notifications
    Add to homescreen

    View Slide

  71. • 43% increase in session
    • 100% increase in engagement
    • 2.5 sec loading time
    • 9x increase in carts recovered

    View Slide

  72. • 100% increase in placed orders

    View Slide

  73. • 65% increase in pages per session
    • 75% increase in tweets sent
    • 20% decrease in bounce rate

    View Slide

  74. • 103% increase of active users
    • 296% increase in session length
    • 406% increase in number of pins
    • 44% increase in ad revenue

    View Slide

  75. • 50kB gzipped - loads in less than 3 second on 2G

    View Slide

  76. • Cut load time from 11.91 to 4.69 seconds
    • 90% smaller than native Android app

    View Slide

  77. Google found that Progressive Web App install banners
    convert 5-6 times more than native install banners

    View Slide

  78. View Slide

  79. View Slide

  80. View Slide

  81. View Slide

  82. secure
    responsive fast
    linkable
    fresh
    installable
    app-like
    re-engageable
    cross
    device
    network
    independent

    View Slide

  83. @maciejtreder

    View Slide