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

Progressive Web Apps - fullStackTO/FITC Web Unleashed

Houssein Djirdeh
September 26, 2017
210

Progressive Web Apps - fullStackTO/FITC Web Unleashed

Houssein Djirdeh

September 26, 2017
Tweet

Transcript

  1. PROGRESSIVE WEB
    APPLICATIONS
    @hdjirdeh

    View Slide

  2. View Slide

  3. View Slide

  4. WEBPAGE
    INGREDIENT
    INGREDIENT
    INGREDIENT
    INGREDIENT
    INGREDIENT
    INGREDIENT

    View Slide

  5. PWAs use modern web capabilities to
    provide a reliable, engaging and fast
    user experience on any device
    reliable engaging fast
    on any device

    View Slide

  6. View Slide

  7. View Slide

  8. NETWORK CONNECTION
    IS SECURE

    View Slide

  9. View Slide

  10. CAN WORK WITH
    POOR/NO CONNECTION

    View Slide

  11. DOWNASAUR

    View Slide

  12. Service workers

    View Slide

  13. A service worker is a script that
    runs in the background of your
    browser when you view a webpage

    View Slide

  14. ADDING A SERVICE WORKER
    1. Create the file and write the logic yourself
    2. Use a library

    View Slide

  15. View Slide

  16. npm install workbox-cli --global
    workbox-cli generate:sw

    View Slide

  17. View Slide

  18. <br/>if ('serviceWorker' in navigator) {<br/>window.addEventListener('load', function () {<br/>navigator.serviceWorker.register('/service-worker.js').then(function(){<br/>// Registration was successful<br/>console.log('ServiceWorker registration successful!');<br/>}).catch(function(err) {<br/>// registration failed :(<br/>console.log('ServiceWorker registration failed: ', err);<br/>});<br/>});<br/>}<br/>
    if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
    navigator.serviceWorker.register('/service-worker.js')
    <br/>if ('serviceWorker' in navigator) {<br/>window.addEventListener('load', function () {<br/>navigator.serviceWorker.register('/service-worker.js').then(function(){<br/>// Registration was successful<br/>console.log('ServiceWorker registration successful!');<br/>}).catch(function(err) {<br/>// registration failed :(<br/>console.log('ServiceWorker registration failed: ', err);<br/>});<br/>});<br/>}<br/>
    <br/>if ('serviceWorker' in navigator) {<br/>window.addEventListener('load', function () {<br/>navigator.serviceWorker.register('/service-worker.js').then(function(){<br/>// Registration was successful<br/>console.log('ServiceWorker registration successful!');<br/>}).catch(function(err) {<br/>// registration failed :(<br/>console.log('ServiceWorker registration failed: ', err);<br/>});<br/>});<br/>}<br/>

    View Slide

  19. View Slide

  20. APPLICATION SHELL

    View Slide

  21. APPLICATION SHELL CONTENT

    View Slide

  22. module.exports = {
    globDirectory: 'dist/',
    globPatterns: ['**/*.{js,png,svg,html,json}'],
    swDest: 'dist/service-worker.js',
    navigateFallback: '/index.html'
    };
    module.exports = {
    globDirectory: 'dist/',
    globPatterns: ['**/*.{js,png,svg,html,json}'],
    swDest: 'dist/service-worker.js',
    navigateFallback: '/index.html',
    };
    module.exports = {
    globDirectory: 'dist/',
    globPatterns: ['**/*.{js,png,svg,html,json}'],
    swDest: 'dist/service-worker.js',
    navigateFallback: '/index.html'
    };
    globDirectory: 'dist/'
    globPatterns: ['**/*.{js,png,svg,html,json}']
    swDest: 'dist/service-worker.js'
    navigateFallback: '/index.html'

    View Slide

  23. BUILD PROCESS

    View Slide

  24. npm install workbox-cli --save-dev
    // package.json
    "scripts": {
    //...
    "build": "{build} && workbox-cli generate:sw"
    }

    View Slide

  25. workbox-webpack-plugin

    View Slide

  26. DYNAMIC CONTENT

    View Slide

  27. module.exports = {
    globDirectory: 'dist/',
    globPatterns: ['**/*.{js,png,svg,html,json}'],
    swDest: 'dist/service-worker.js',
    navigateFallback: '/index.html',
    runtimeCaching: [
    {
    urlPattern: /^https:\/\/your.api.com\/.*/,
    handler: 'networkFirst'
    }
    ]
    };
    module.exports = {
    globDirectory: 'dist/',
    globPatterns: ['**/*.{js,png,svg,html,json}'],
    swDest: 'dist/service-worker.js',
    navigateFallback: '/index.html',
    runtimeCaching: [
    {
    urlPattern: /^https:\/\/your.api.com\/.*/,
    handler: 'networkFirst'
    }
    ]
    };
    runtimeCaching: [
    {
    urlPattern: /^https:\/\/your.api.com\/.*/,
    handler: 'networkFirst'
    }
    ]
    runtimeCaching: [
    {
    urlPattern: /^https:\/\/your.api.com\/.*/,
    handler: 'networkFirst'
    }
    ]
    networkFirst

    View Slide

  28. networkFirst
    cacheFirst
    fastest
    cacheOnly
    networkOnly

    View Slide

  29. APP SHELL
    +
    DYNAMIC CACHING

    View Slide

  30. OFFLINE SUPPORT
    +
    FASTER REPEAT VISITS

    View Slide

  31. View Slide

  32. preview.starbucks.com

    View Slide

  33. CAN I HAZ?
    Under development

    View Slide

  34. PAGE LOAD IS FAST

    View Slide

  35. View Slide

  36. CSS
    JS
    PNG

    View Slide












  37. View Slide

  38. JS
    JS

    View Slide


  39. as="script"

    as="style"
    as="font"
    as="audio"
    as="image"
    as="video"

    View Slide


  40. View Slide

  41. preload-webpack-plugin


    View Slide

  42. CAN I HAZ?
    Partial Support

    View Slide

  43. HTTP/2 Server Push

    View Slide

  44. View Slide

  45. View Slide

  46. Link: ; rel=preload; as=style
    Link: ; rel=preload; as=script

    View Slide

  47. View Slide

  48. Link: ; rel=preload; as=style; nopush
    Link: ; rel=preload; as=script

    View Slide

  49. A Comprehensive Guide To HTTP/2 Server Push - Jeremy Wagner
    https://rebrand.ly/http2

    View Slide

  50. Pushing too much
    Pushing unused assets
    Cache?

    View Slide

  51. Service Worker
    H2 Push

    View Slide

  52. BUNDLES

    View Slide

  53. 4KB - 145KB
    Size of JS frameworks, gzipped
    Restuta/framework-sizes.md GIST

    View Slide

  54. CODE SPLITTING

    View Slide

  55. export const routes: Routes = [
    { path: '', redirectTo: 'main', pathMatch: 'full' },
    { path: 'main', component: MainComponent },
    { path: 'details', loadChildren: 'details/details.module#DetailsModule' }
    ];
    export const routes: Routes = [
    { path: '', redirectTo: 'main', pathMatch: 'full' },
    { path: 'main', component: MainComponent },
    { path: 'details', loadChildren: 'details/details.module#DetailsModule' }
    ];
    loadChildren: 'details/details.module#DetailsModule'

    View Slide

  56. import Loadable from 'react-loadable';
    import Loading from './loading.component';
    const LoadableComponent = Loadable({
    loader: () => import('./details.component'),
    loading: Loading,
    });

    View Slide

  57. View Slide

  58. WEBPACK BUNDLE ANALYZER

    View Slide

  59. bundlesize

    View Slide

  60. FIRST MEANINGFUL PAINT
    TIME TO INTERACTIVE

    View Slide

  61. SHOW SOME CONTENT
    WITHOUT JAVASCRIPT

    View Slide


  62. Sorry, JavaScript needs to be enabled in
    order to run this application.

    View Slide

  63. SERVER SIDE RENDERING

    View Slide

  64. INSTALL ON
    YOUR DEVICE

    View Slide


  65. View Slide

  66. {
    name: "Angular 2 HN",
    short_name: "Angular 2 HN",
    icons: [
    {
    src: "assets/icons/android-chrome-192x192.png",
    sizes: "192x192",
    type: "image/png"
    },
    // ...
    ],
    theme_color: "#b92b27",
    background_color: "#ffffff",
    display: "standalone",
    orientation: "portrait"
    }

    View Slide

  67. APP INSTALL BANNER

    View Slide

  68. INSTALL TO HOMESCREEN

    View Slide

  69. SPLASH SCREEN

    View Slide

  70. APP LOADED

    View Slide

  71. CAN I HAZ?
    Under development

    View Slide

  72. SAFARI ON IOS
    Can install to homescreen
    but that’s it…

    View Slide













  73. View Slide

  74. View Slide

  75. View Slide

  76. Native
    Progressive Web

    View Slide

  77. Progressive web apps can replace native apps

    View Slide

  78. @hdjirdeh

    View Slide