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

The Unbearable Weight of Massive JavaScript – performance.now()

The Unbearable Weight of Massive JavaScript – performance.now()

Follow Ryan on Mastodon @ https://webperf.social/@ryantownsend

For the past 10+ years, JavaScript frameworks and Single Page Applications have been marketed as the solution to all our performance, robustness and productivity problems, but things haven’t worked out the way we’d all hoped, have they?

* Simple marketing and ecommerce sites are still getting heavier and slower.

* Features fail in weird and wonderful ways meaning we need an ever-increasing array of tooling to monitor and debug problems.

* Teams armed with the latest Apple Silicon Macs, expensive CI tooling and complex build pipelines still can’t ship effectively.

But it’s not all doom-and-gloom: we live in a time of unprecedented opportunity to give our users a fantastic experience – the web platform has never been more capable than it is today.

Let’s look at what we can achieve by simplifying our web architecture, utilising new and upcoming Web Platform APIs and getting back to building fast, maintainable, user-friendly front-ends.

Ryan Townsend

November 01, 2023
Tweet

More Decks by Ryan Townsend

Other Decks in Programming

Transcript

  1. The Unbearable Weight of
    Massive JavaScript

    View full-size slide

  2. twnsnd.com/perfnow

    View full-size slide

  3. twnsnd.com/perfnow
    How did our priorities get misaligned?


    What it really means to be productive


    How we can improve things with the Web Platform

    View full-size slide

  4. twnsnd.com/perfnow
    Web Platform-
    fi
    rst

    View full-size slide

  5. twnsnd.com/perfnow

    View full-size slide

  6. twnsnd.com/perfnow
    Up to 2 years
    3 to 5 years
    5 to 10 years
    10 to 20 years
    How long?! 😬
    0% 1,600%
    Years of Experience

    View full-size slide

  7. twnsnd.com/perfnow
    img.png { behavior: url(png.htc) }

    View full-size slide

  8. twnsnd.com/perfnow
    No ever-green browsers


    Front-end development
    ‘Not SERIOUS’


    Inaccessible Macromedia Adobe Flash


    What even is
    ‘Automated testing’?


    Rudimentary web performance tooling

    View full-size slide

  9. twnsnd.com/perfnow
    Reach a global audience


    Iterate faster than any other platform


    Lower disparity in connectivity and compute


    ‘Progressive Enhancement’ and ‘Graceful Degradation’ coined


    Web Standards movement headway on consistency

    View full-size slide

  10. Real world projects BIG TECH & VC DEMOS

    View full-size slide

  11. twnsnd.com/perfnow

    View full-size slide

  12. twnsnd.com/perfnow

    View full-size slide

  13. twnsnd.com/perfnow
    Trickle-down User Experience

    View full-size slide

  14. twnsnd.com/perfnow
    “92% [of businesses] think their website’s


    poor user experience is costing them sales”
    — Storyblok Research

    View full-size slide

  15. twnsnd.com/perfnow
    Janky sliders
    Multi-megabyte
    JavaScript resources for
    static landing pages
    Tracking-dependent add-to-cart
    Unhoverable mega-menus
    In
    fi
    nite loops
    Skeletons for infrequently
    changed content
    Accept cookies! Live chat now!
    Sign-up for 10% o
    ff
    !
    Client-side rendered forms
    2.5mb marketing landing pages

    View full-size slide

  16. twnsnd.com/perfnow

    View full-size slide

  17. twnsnd.com/perfnow

    View full-size slide

  18. twnsnd.com/perfnow
    We can do better

    View full-size slide

  19. twnsnd.com/perfnow
    Developer Experience Convenience

    View full-size slide

  20. twnsnd.com/perfnow
    Productivity is more than


    n
    p
    m i
    ns
    ta
    l
    l

    View full-size slide

  21. twnsnd.com/perfnow

    View full-size slide

  22. twnsnd.com/perfnow
    Performance


    Accessibility


    Usability


    Talent Availability & Retention


    Maintainability


    Security


    Reliability & Robustness


    Onboarding & Training

    View full-size slide

  23. twnsnd.com/perfnow
    Performance


    Accessibility


    Usability


    Talent Availability & Retention


    Maintainability


    Security


    Reliability & Robustness


    Onboarding & Training

    View full-size slide

  24. twnsnd.com/perfnow
    A necessary but costly decision

    View full-size slide

  25. twnsnd.com/perfnow

    View full-size slide

  26. twnsnd.com/perfnow

    View full-size slide

  27. twnsnd.com/perfnow
    Tell me you’ve migrated to an SPA


    without telling me you’ve migrated to an SPA

    View full-size slide

  28. twnsnd.com/perfnow
    “It would be better if it was more ’APP-LIKE’”
    — Nobody, not a single end-user

    View full-size slide

  29. twnsnd.com/perfnow

    View full-size slide

  30. twnsnd.com/perfnow
    Consistently working


    Reasonably fast


    Accessible


    Usable

    View full-size slide

  31. twnsnd.com/perfnow
    Performance


    Accessibility


    Usability


    Talent Availability & Retention


    Maintainability


    Security


    Reliability & Robustness


    Onboarding & Training
    “It depends”

    View full-size slide

  32. twnsnd.com/perfnow
    Few are ready

    View full-size slide

  33. twnsnd.com/perfnow
    Embracing the Web Platform

    View full-size slide

  34. twnsnd.com/perfnow
    “Consider users over authors over implementors
    over speci
    fi
    ers over theoretical purity”
    — W3C’s Priority of Constituencies


    (within the HTML Design Principles)
    That’s us!

    View full-size slide

  35. twnsnd.com/perfnow

    View full-size slide

  36. twnsnd.com/perfnow
    55,000 lines of JavaScript

    View full-size slide

  37. twnsnd.com/perfnow
    1. Import Maps


    2. Custom Elements


    3. Scroll-snapping / Scroll-linked Animations


    4. View Transitions


    5. Navigation API

    View full-size slide

  38. twnsnd.com/perfnow
    BUT FIRST!


    A few important words on approach

    View full-size slide

  39. twnsnd.com/perfnow
    Progressive Enhancement

    View full-size slide

  40. twnsnd.com/perfnow
    Sending useful HTML: forms, links, buttons


    Accepting there will be bugs in your software


    Ensuring every feature works without JavaScript, regardless of importance


    Going cold-turkey on frameworks & libraries

    View full-size slide

  41. twnsnd.com/perfnow
    Browser support

    View full-size slide

  42. twnsnd.com/perfnow

    View full-size slide

  43. twnsnd.com/perfnow

    View full-size slide

  44. twnsnd.com/perfnow
    Waiting for all browsers to support a feature


    Waiting for everyone to update their browser


    Developing against the lowest common denominator


    Using features which bene
    fi
    t signi
    fi
    cant portions of your customer base

    View full-size slide

  45. twnsnd.com/perfnow
    Poly
    fi
    lls, Shims &


    alternative code paths

    View full-size slide

  46. twnsnd.com/perfnow
    Making it work for everyone, regardless of performance impact


    Using poly
    fi
    lls that provide support back to the stone age


    Using massive fully-featured poly
    fi
    lls, when an if/else would do


    Never reviewing what poly
    fi
    lls you still have in play


    Giving more of your customer base a great experience

    View full-size slide

  47. twnsnd.com/perfnow
    Import Maps
    Shimmable!

    View full-size slide

  48. twnsnd.com/perfnow
    <br/><br/><br/>{<br/><br/><br/>"imports": {<br/><br/><br/>"shared-library-1.js": "./shared-library-1-a1b2c3.js",<br/><br/><br/>"shared-library-2.js": "./shared-library-2-d4e5f6.js"<br/><br/><br/>}<br/><br/><br/>}<br/><br/><br/>

    View full-size slide

  49. twnsnd.com/perfnow
    import { feature } from "shared-library-1.js";


    /* actually loads shared-library-1-a1b2c3.js */

    View full-size slide

  50. twnsnd.com/perfnow
    <br/><br/><br/>{<br/><br/><br/>"imports": {<br/><br/><br/>"third-party.js": "https://example.com/third-party.js"<br/><br/><br/>}<br/><br/><br/>}<br/><br/><br/>
    JUST BECAUSE YOU CAN, DOESN’T MEAN YOU SHOULD

    View full-size slide

  51. twnsnd.com/perfnow
    shared-library.js
    file-one.js file-two.js file-three.js
    import { feature } from "shared-library.js"

    View full-size slide

  52. twnsnd.com/perfnow
    shared-library-v1.js
    file-one-v1.js file-two-v1.js file-three-v1.js
    import { feature } from "shared-library-v1.js"

    View full-size slide

  53. twnsnd.com/perfnow
    shared-library-v2.js
    file-one-v1.js file-two-v1.js file-three-v1.js
    import { feature } from "shared-library-v1.js"

    View full-size slide

  54. twnsnd.com/perfnow
    shared-library-v2.js
    file-one-v1.js file-two-v1.js file-three-v1.js
    import { feature } from "shared-library-v2.js"

    View full-size slide

  55. twnsnd.com/perfnow
    shared-library-v2.js
    file-one-v2.js file-two-v2.js file-three-v2.js
    import { feature } from "shared-library-v2.js"

    View full-size slide

  56. twnsnd.com/perfnow
    Improved cache hit ratio


    More simple, faster build pipelines


    Lower reliance on bundling * YMMV - see shared dictionarY compression


    Therefore, better prioritisation of individual scripts
    Import Maps

    View full-size slide

  57. twnsnd.com/perfnow
    <br/><br/><br/>{<br/><br/><br/>"imports": {<br/><br/><br/>"shared-import.js": "./shared-import-e5f6.js"<br/><br/><br/>}<br/><br/><br/>}<br/><br/><br/>






    View full-size slide

  58. twnsnd.com/perfnow

    View full-size slide

  59. twnsnd.com/perfnow
    Shadow DOM
    Light DOM

    View full-size slide

  60. twnsnd.com/perfnow
    Shadow DOM
    Light DOM

    View full-size slide

  61. twnsnd.com/perfnow













    View full-size slide

  62. twnsnd.com/perfnow
    class MyCustomElement extends HTMLElement {


    connectedCallback() {


    // added to DOM, attach events, initialize etc


    }


    disconnectedCallback() {


    // removed from DOM, detach events, cleanup etc


    }


    }


    customElements.define("my-custom-element", MyCustomElement)

    View full-size slide

  63. twnsnd.com/perfnow
    class MyCustomElement extends HTMLElement {


    static get observedAttributes() {


    return ["my-attribute"]


    }


    attributeChangedCallback(name, oldValue, newValue) {


    // action attribute changes


    }


    }


    View full-size slide

  64. twnsnd.com/perfnow
    class MyCustomElement extends HTMLElement {


    static observedAttributes = ["value"]


    static formAssociated = true


    #internals


    constructor() {


    super()


    this.#internals = this.attachInternals()


    }


    attributeChangedCallback(name, oldValue, newValue) {


    this.#internals.setFormValue(newValue)


    }


    }

    View full-size slide

  65. twnsnd.com/perfnow
    my-custom-element:defined {


    /* active styling */


    }


    my-custom-element:not(:defined) {


    /* inactive styling */


    }

    View full-size slide

  66. twnsnd.com/perfnow
    You may not need to use slots or the (Declarative) Shadow DOM


    Your custom element can just use querySelector and innerHTML


    You may not need isomorphic rendering


    Some duplication is probably
    fi
    ne (though, alternatives do exist)
    Don’t over-complicate it
    LIT, WEBC, ENHANCE

    View full-size slide

  67. twnsnd.com/perfnow
    Scroll Snapping &


    Scroll-Linked Animations

    View full-size slide

  68. twnsnd.com/perfnow
    Progressive Enhancement


    ~10 lines of CSS


    Zero JavaScript


    GPU-accelerated
    Scroll Snap

    View full-size slide

  69. twnsnd.com/perfnow
    .parent {


    overflow: hidden;


    overflow-x: auto;


    scroll-snap-type: x mandatory;


    scroll-snap-stop: always;


    scroll-behavior: smooth;


    overscroll-behavior-inline: contain;


    -webkit-overflow-scrolling: touch;


    scrollbar-width: none;


    }


    .parent::-webkit-scrollbar { display: none }


    .parent > * { scroll-snap-align: start }

    View full-size slide

  70. twnsnd.com/perfnow

    View full-size slide

  71. twnsnd.com/perfnow
    Progressive Enhancement


    ~10 lines of CSS


    Zero JavaScript


    Poly
    fi
    lled with Intersection Observer
    Scroll-Linked Animation
    (Position: Support)

    IMPLEMENTATION EN-ROUTE!

    View full-size slide

  72. twnsnd.com/perfnow
    @supports (scroll-timeline: --name inline) {


    @keyframes fade-in {


    0% { opacity: 0 }


    1% { opacity: 1 }


    }


    scrollable-element {


    scroll-timeline: --scroll-shadow inline;


    }


    scrollable-element .scroll-shadow-inline-start,


    scrollable-element .scroll-shadow-inline-end {


    animation: auto fade-in linear forwards;


    animation-timeline: --scroll-shadow;


    }


    scrollable-element .scroll-shadow-inline-end {


    animation-direction: reverse;


    }


    }

    View full-size slide

  73. twnsnd.com/perfnow
    if (!CSS.supports("(scroll-timeline: --name inline)")) {


    customElements.define("scroll-indicator", ScrollIndicator)


    if (window.matchMedia("(min-width: 1024px)").matches) {


    customElements.define("scroll-shadow", ScrollShadow)


    }


    }

    View full-size slide

  74. twnsnd.com/perfnow
    View Transitions

    View full-size slide

  75. twnsnd.com/perfnow
    SPAs are a big trade-o
    ff

    just for page transitions

    View full-size slide

  76. twnsnd.com/perfnow
    Nobody likes having their
    toys taken away

    View full-size slide

  77. twnsnd.com/perfnow
    Progressive Enhancement


    As little as 1 line of HTML


    Zero JavaScript


    GPU-accelerated
    Cross-document Transitions
    (Position:UNKNOWN)

    View full-size slide

  78. twnsnd.com/perfnow

    View full-size slide

  79. twnsnd.com/perfnow
    view-transition-name: my-element

    View full-size slide

  80. twnsnd.com/perfnow
    ::view-transition-old(my-element) {


    animation: fade 0.3s ease forwards


    }


    ::view-transition-new(my-element) {


    animation: fade 0.3s ease reverse


    }


    @keyframes fade {


    from { opacity: 1 }


    to { opacity: 0 }


    }

    View full-size slide

  81. twnsnd.com/perfnow

    View full-size slide

  82. twnsnd.com/perfnow
    Progressive Enhancement


    ~5 lines of JavaScript (inc. fallback)


    Customise with CSS


    GPU-accelerated
    Single-document Transitions
    (Position:POSITIVe/SUPPORT)

    View full-size slide

  83. twnsnd.com/perfnow
    function navigateWithTransition(data) {


    // fallback


    if (!document.startViewTransition) {


    updateDOM(data)


    return


    }


    document.startViewTransition(() => updateDOM(data))


    }

    View full-size slide

  84. twnsnd.com/perfnow
    Navigation API
    (Position: POSITIVE/Support)

    View full-size slide

  85. twnsnd.com/perfnow
    Manually attach submit/click event listeners


    Manually implement loading feedback


    Manually announce page changes


    Manually manage scroll position
    History API

    View full-size slide

  86. twnsnd.com/perfnow
    navigation.addEventListener("navigate", (event) => {


    if (!event.canIntercept) return




    event.intercept({


    async handler() {


    const content = await loadContent(event.destination.url)


    renderContent(content)


    }


    })


    })

    View full-size slide

  87. twnsnd.com/perfnow
    navigation.addEventListener("navigate", (event) => {


    if (!event.canIntercept) return




    event.intercept({


    async handler() {


    const content = await loadContent(event.destination.url)


    document.startViewTransition(() => renderContent(content))


    }


    })


    })

    View full-size slide

  88. twnsnd.com/perfnow
    Decoupled from the DOM


    Native browser loading state


    Native accessibility technology integration


    Handles restoring scroll position for you
    Navigation API

    View full-size slide

  89. twnsnd.com/perfnow
    Bonus noteworthy mentions

    View full-size slide

  90. twnsnd.com/perfnow
    CSS Toggles

    View full-size slide

  91. twnsnd.com/perfnow
    • Push Notifications


    • Badging API


    • WebShare API


    • PassKeys


    • Anchor Positioning


    • Container Queries


    • Cascade Layers


    • :user-valid / :user-invalid


    • Popover API


    • Deferred Fetch


    • Internationalisation API


    • Web Workers


    • OffscreenCanvas


    • WASM

    View full-size slide

  92. twnsnd.com/perfnow
    Use the Web Platform,


    don’t reimplement it

    View full-size slide

  93. twnsnd.com/perfnow
    How’re those stats looking?

    View full-size slide

  94. twnsnd.com/perfnow
    55,000650 lines of JavaScript

    View full-size slide

  95. twnsnd.com/perfnow

    View full-size slide

  96. twnsnd.com/perfnow

    View full-size slide

  97. twnsnd.com/perfnow
    1. Know your audience


    2. Don’t limit yourself to fully-adopted features


    3. Consider the standard positions of browsers, not just support


    4. Consider the maturity of standards


    5. Consider how far back and how wide your poly
    fi
    lls need to go

    View full-size slide

  98. twnsnd.com/perfnow
    Thank you!

    View full-size slide