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

Once you go PRPL - FullStackFest

Houssein Djirdeh
September 07, 2017
26

Once you go PRPL - FullStackFest

Houssein Djirdeh

September 07, 2017
Tweet

Transcript

  1. XKCD/Installing

    View Slide

  2. Once you go PRPL…
    @hdjirdeh

    View Slide

  3. PUSH critical resources
    RENDER initial route
    PRE-CACHE resources
    LAZY LOAD remaining routes
    P
    R
    L
    P

    View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. CSS

    View Slide

  9. JS

    View Slide

  10. PNG

    View Slide












  11. View Slide

  12. JS
    JS

    View Slide


  13. as="script"

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

    View Slide


  14. View Slide

  15. preload-webpack-plugin


    View Slide

  16. CAN I HAZ?
    Partial Support

    View Slide

  17. HTTP/2 Server Push

    View Slide

  18. View Slide

  19. View Slide

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

    View Slide

  21. View Slide

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

    View Slide

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

    View Slide

  24. Pushing too much

    View Slide

  25. Pushing unused assets

    View Slide

  26. Cache?

    View Slide

  27. PUSH critical resources

    View Slide

  28. View Slide

  29. Service workers

    View Slide

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

    View Slide

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

    View Slide

  32. View Slide

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

    View Slide

  34. View Slide

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

  36. View Slide

  37. APPLICATION SHELL

    View Slide

  38. APPLICATION SHELL CONTENT

    View Slide

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

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

    View Slide

  41. workbox-webpack-plugin

    View Slide

  42. DYNAMIC CONTENT

    View Slide

  43. 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'
    }
    ]
    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'
    }
    ]
    };
    networkFirst
    cacheFirst
    fastest
    cacheOnly
    networkOnly
    runtimeCaching: [
    {
    urlPattern: /^https:\/\/your.api.com\/.*/,
    handler: 'networkFirst'
    }
    ]

    View Slide

  44. 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'
    }
    ]
    networkFirst

    View Slide

  45. networkFirst

    View Slide

  46. networkFirst
    cacheFirst
    fastest
    cacheOnly
    networkOnly

    View Slide

  47. APP SHELL
    +
    DYNAMIC CACHING

    View Slide

  48. OFFLINE SUPPORT
    +
    FASTER REPEAT VISITS

    View Slide

  49. CAN I HAZ?
    Under development

    View Slide

  50. Service Worker
    H2 Push

    View Slide

  51. PRE-CACHE resources

    View Slide

  52. BUNDLES

    View Slide

  53. 4KB - 200KB
    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. 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

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

    View Slide

  58. View Slide

  59. WEBPACK BUNDLE ANALYZER

    View Slide

  60. bundlesize

    View Slide

  61. LAZY LOAD remaining routes

    View Slide

  62. PRPL
    PUSH critical resources
    RENDER initial route
    PRE-CACHE resources
    LAZY LOAD remaining routes

    View Slide

  63. TIME TO INTERACTIVE
    FIRST PAINT

    View Slide

  64. View Slide

  65. @hdjirdeh

    View Slide