$30 off During Our Annual Pro Sale. View Details »

Web performance optimisation for single page applications

Web performance optimisation for single page applications

Accompanying slides to a 4 hour course on monitoring and web performance optimisation for single page applications

Stefan Baumgartner

February 06, 2017
Tweet

More Decks by Stefan Baumgartner

Other Decks in Programming

Transcript

  1. WPO for SPAs
    The epic battle against loading indicators

    View Slide

  2. Stefan Baumgartner
    Internet Batman
    Larry Urbano
    Senior Sales Engineer
    Monitoring redefined

    View Slide

  3. Agenda
    1. Some theory
    2.We meet our Single Page Application
    3.Performance optimisation techniques
    4.Some live coding and lots of demos

    View Slide

  4. Title Text
    Breaks

    View Slide

  5. Subheadline

    View Slide

  6. Why have we moved to SPAs?

    View Slide

  7. Client
    Client
    Initial request
    HTML payload
    Form POST
    HTML payload
    Traditional

    View Slide

  8. Client
    Client
    Initial request
    HTML payload
    AJAX call via JS
    HTML Diff
    SPA

    View Slide

  9. Single Page Applications are awesome …
    ▪ They provide better UX once loaded
    ▪ Communication is reduced to deltas
    ▪ This results in fewer requests and smaller payload
    ▪ Should your Network die, you still have some content available
    ▪ They’re super-easy to deploy

    View Slide

  10. Single Page Applications are hard…
    ▪ The client is in control… but the client starts when everything has
    been transferred
    ▪ The client side app has to take care of all the errors and has to be a
    lot lot smarter
    ▪ Flaky networks harm the UX
    ▪ Fallbacks are hard
    ▪ Bad practices are more seductive
    ▪ States are hard to share

    View Slide

  11. Client
    Client
    Initial request
    non-content HTML
    AJAX call via JS
    content diff
    SPAs
    Resource request
    JavaScript payload
    Initial AJAX call via JS
    content payload

    View Slide

  12. Client
    Client
    Initial request
    non-content HTML
    AJAX call via JS
    content diff
    SPAs
    Resource request
    JavaScript payload
    Initial AJAX call via JS
    content payload
    What is going on here?

    View Slide

  13. View Slide

  14. Subheadline

    View Slide

  15. initial HTML request
    angular.js
    main.js
    data/from/backend

    View Slide

  16. All of them?

    View Slide

  17. prompt for
    unload
    redirect DNS TCP Request Response Processing onLoad
    navigationStart
    redirectStart
    redirectEnd
    domainLookupStart
    domainLookupEnd
    connectStart
    connectEnd
    requestStart
    responseStart responseEnd
    domLoading
    domInteractive
    domContentLoaded
    domComplete
    loadEventStart
    loadEventEnd

    View Slide

  18. prompt for
    unload
    redirect DNS TCP Request Response Processing onLoad
    navigationStart
    redirectStart
    redirectEnd
    domainLookupStart
    domainLookupEnd
    connectStart
    connectEnd
    requestStart
    responseStart responseEnd
    domLoading
    domInteractive
    domContentLoaded
    domComplete
    loadEventStart
    loadEventEnd

    View Slide

  19. domLoading
    domInteractive
    domContentLoaded
    domComplete

    View Slide

  20. domLoading
    domInteractive
    domContentLoaded
    domComplete
    The DOM is getting parsed
    DOM is parsed and ready to work on
    The document is loaded (wo stylesheets, images)
    All sub resources are loaded

    View Slide

  21. Let’s check our SPA
    Demo-time

    View Slide

  22. View Slide

  23. cd /app/twitterwall-server
    npm start
    service nginx start

    View Slide

  24. cd /app/twitterwall-client-webpack
    (commands to follow)

    View Slide

  25. replace contents of
    /app/twitterwall-server/public
    with
    /app/twitterwall-client-webpack/dist

    View Slide

  26. npm stop
    npm start

    View Slide

  27. Step 1: Production builds
    Put back your development pride

    View Slide

  28. CSS
    JS

    View Slide

  29. CSS
    JS

    View Slide

  30. CSS
    JS VENDOR

    View Slide

  31. CSS
    JS
    VENDOR

    View Slide

  32. Step 2: Tree shaking
    It’s not as funny as it sounds. But equally cool

    View Slide

  33. ESnext module syntax
    ▪ EcmaScript finally has a module syntax (and probably a module
    loading strategy soon as well!)
    ▪ Tooling allows us to use this new syntax already
    import { createServer } from ‘http’;
    import * as path from ‘path’;
    export function cube(x) { return x*x*x; }
    export default { … }
    const createServer =
    require(‘http’).createServer;
    const path = require(‘path’);
    module.exports = {
    cube: function(x) { return x*x*x}
    }

    View Slide

  34. Tree Shaking
    ▪ This new syntax allows tools to do a static code analysis based on
    the JavaScript AST.
    ▪ With that, we can exclude functions we simply do not need,
    reducing our bundle size even more.

    View Slide

  35. Angular Ahead of Time compilation
    ▪ Faster rendering: With AOT, the browser downloads a pre-compiled
    version of the application. The browser loads executable code so it
    can render the application immediately, without waiting to compile
    the app first.
    ▪ Fewer asynchronous requests: The compiler inlines external html
    templates and css style sheets within the application JavaScript,
    eliminating separate ajax requests for those source files.

    View Slide

  36. Angular Ahead of Time compilation
    ▪ Smaller Angular framework download size: There’s no need to
    download the Angular compiler if the app is already compiled. The
    compiler is roughly half of Angular itself, so omitting it dramatically
    reduces the application payload.
    ▪ Detect template errors earlier: The AOT compiler detects and
    reports template binding errors during the build step before users
    can see them.
    ▪ Better security: AOT compiles HTML templates and components
    into JavaScript files long before they are served to the client. With
    no templates to read and no risky client-side HTML or JavaScript
    evaluation, there are fewer opportunities for injection attacks

    View Slide

  37. Step 3: SSR
    Putting the server back into the equation

    View Slide

  38. initial HTML request
    angular.js
    main.js
    data/from/backend
    Start render

    View Slide

  39. initial HTML request
    angular.js
    main.js
    data/from/backend
    Start render?

    View Slide

  40. The network is a bottle-neck

    View Slide

  41. So make every request count!

    View Slide

  42. Client
    Client
    Initial request
    non-content HTML
    AJAX call via JS
    content diff
    Resource request
    JavaScript payload
    Initial AJAX call via JS
    content payload
    App

    View Slide

  43. Client
    Client
    Initial request
    Initial Render HTML
    AJAX call via JS
    content diff
    Resource request
    JavaScript payload
    Initial AJAX call via JS
    content payload
    App
    App

    View Slide

  44. Important content first
    Everything else is an enhancement

    View Slide

  45. Server side rendering for SPAs
    ▪ Thanks to a little technology called Node.js, we are able to render
    JS on the client and the server
    ▪ As long as you have valid routes (= URLs), you have the ability to
    render the state on the server
    ▪ The first requests bring the rendered state
    ▪ Then the JavaScript framework kicks in

    View Slide

  46. View Slide

  47. View Slide

  48. View Slide

  49. But I can’t move all by backend to
    Node.js

    View Slide

  50. You don’t have to!

    View Slide

  51. View Slide

  52. Bonus round!
    Lazy loaded routes

    View Slide

  53. Bundling …
    ▪ Why bundle everything, when we just need a few things to start?
    ▪ Routes deep down in the navigation might not be used at all…
    ▪ Bundle by routes, split away code that you don’t need at first…

    View Slide

  54. Bonus round!
    Responsive images

    View Slide

  55. srcset="screenshot-200.png 200w,
    screenshot-400.png 400w,
    screenshot-600.png 600w,
    screenshot-800.png 800w,
    screenshot-1000.png 1000w,
    screenshot-1200.png 1200w,
    screenshot-1400.png 1400w,
    screenshot-1600.png 1600w”
    sizes="(min-width: 900px) 50vw, 100vw"
    alt=”Super screenshot of our product.">

    View Slide

  56. srcset="screenshot-200.png 200w,
    screenshot-400.png 400w,
    screenshot-600.png 600w,
    screenshot-800.png 800w,
    screenshot-1000.png 1000w,
    screenshot-1200.png 1200w,
    screenshot-1400.png 1400w,
    screenshot-1600.png 1600w”
    sizes="(min-width: 900px) 50vw, 100vw"
    alt=”Super screenshot of our product.">
    A low-res fallback image for browsers that don’t know srcset
    These sources are available. For each “width unit”
    there’s a reduced version of our original screenshot
    The sizes define which source to choose from. Retina screens
    are also checked

    View Slide

  57. s
    Subheadline
    Speed Index

    View Slide

  58. View Slide

  59. View Slide

  60. ∫ 1 - visuallycomplete/100
    0
    end

    View Slide

  61. What does this mean?

    View Slide

  62. View Slide

  63. View Slide

  64. View Slide

  65. View Slide

  66. Visually complete (%)
    0
    25
    50
    75
    100
    Time in Seconds
    0s 1s 2s 3s 4s 5s 6s 7s 8s

    View Slide

  67. Visually complete (%)
    0
    25
    50
    75
    100
    Time in Seconds
    0s 1s 2s 3s 4s 5s 6s 7s 8s

    View Slide

  68. Visually complete (%)
    0
    25
    50
    75
    100
    Time in Seconds
    0s 1s 2s 3s 4s 5s 6s 7s 8s

    View Slide

  69. s
    Subheadline
    Thoughts
    about HTTP2

    View Slide

  70. Server
    Client
    HTTP/2
    Getting stuff …
    GET
    image1
    image1
    header
    image1
    payload
    image1
    payload
    image2
    header
    image2
    payload
    image1
    payload
    image2
    payload
    GET
    image2

    View Slide

  71. HTTP 1.1
    index.html
    a.js
    b.js
    c.js
    d.js

    View Slide

  72. HTTP 2
    index.html
    a.js
    b.js
    c.js
    d.js

    View Slide

  73. HTTP 2
    index.html
    a.js
    b.js
    c.js
    d.js

    View Slide

  74. HTTP 2
    index.html
    a.js
    b.js
    c.js
    d.js

    View Slide

  75. View Slide

  76. Desktop
    HTTP/2 ~1.8s
    HTTP1.1 ~2.6s

    View Slide

  77. mobile connections
    HTTP1.1 ~3.37s
    HTTP2 ~1.72

    View Slide

  78. A slow website on HTTP1.1 will
    still be a slow website on HTTP2

    View Slide

  79. Frequency of change
    Libraries
    Utilities
    Module Module Module Module
    rigid
    high
    frequency
    some
    frequency

    View Slide

  80. Optimised utility layer
    Libraries
    Utilities
    Module Module Module
    rigid
    high
    frequency
    some
    frequency

    View Slide

  81. Extending the utility layer
    Libraries
    Utilities
    Module Module Module
    rigid
    high
    frequency
    some
    frequency

    View Slide

  82. Files to change
    Libraries
    Utilities
    Module Module Module
    rigid
    high
    frequency
    some
    frequency

    View Slide

  83. Frequency of change
    Libraries
    Module Module Module
    rigid
    high
    frequency
    Module

    View Slide

  84. What to do with
    your application?

    View Slide

  85. The best request is
    a request not being made

    View Slide

  86. Create independent,
    exchangeable components

    View Slide

  87. Create small,
    detached bundles

    View Slide

  88. Code duplication and weight is okay
    if the file can stay longer

    View Slide

  89. Think about long lasting applications
    and frequency of change

    View Slide

  90. Thank you.

    View Slide