Live Demo đ All Demo, No Pitch: Content & Commerce / Builder.io & Elastic Path on 12/13
Use Cases
Pricing
Blog
Ă
Visual CMS
Drag-and-drop visual editor and headless CMS for any tech stack
Theme Studio for Shopify
Build and optimize your Shopify-hosted storefront, no coding required
Resources
Blog
Get StartedLoginâ°
Today, websites are more interactive and useful than ever, which also means theyâre more complex than ever. Users have come to expect the new interactivity and usefulness, and theyâre not going to want to give it up. All of this means more JavaScript is being sent to the browser on page load than ever, which isnât likely to slow down anytime soon. We can expect that sites will continue to keep getting better and more complex, but what should we do about JavaScript?
Itâs well understood that the amount of JavaScript being sent to browsers is steadily increasing, as shown in this graph from httparchive.org.
Some people like to argue that the site we served ten years ago and the one we serve today are the same. But itâs not a fair comparison. The sites of today are way more complex.
And while some of the complexity comes from better interactions and functionality for the end-users, a lot of it comes from helping us gain insight into our users' behavior, which helps us build even better sites. Our sites ultimately get bigger because they do more stuff not only for our end-users, but for us as well.
Every year, the CPUs are getting faster, but most of the speedup comes from improved parallelism. And in recent years the performance improvements per core have been slowing down. Weâre approaching the limits of how fast CPU clocks can run and how much cleverness the CPUs can do per clock cycle. As a result, we see more multi-core CPUs pop up (It is not uncommon for your phone to have 4 CPU cores and 4 GPU cores). So the main driver of CPU performance improvement these days comes from parallelism of multiple cores, not from improvements in a single core.
So, why are we talking about CPU speed and cores? As our sites get bigger and download more JavaScript, the CPU has more work to do. And because JavaScript is single-threaded, all of the additional work falls onto a single core. Therefore, this is not a problem that will get better by waiting a few years and expecting the hardware to catch up.
Ultimately, our current JS load is increasing faster than the rate of single CPU core performance. This is not sustainable.
Frameworks for desktop applications have existed way before the web. So when the web came, we just took our desktop framework philosophy of what the framework is and applied it to the web. Desktop frameworks can safely assume that all of the code is already available and that there is no server. The problem is that those two key points are not true for the web. We can't assume that the code is already available, and server pre-rendering has become an important part of our vocabulary.
Weâre at a stage where the frameworks we have are pretending theyâre desktop frameworks. They have not embraced SSR and lazy-loading to the core.
An application needs to boot up on the client. The bootup consists of a fixed cost of the framework and a variable cost of the application itself (the complexity of the application). So really, we are talking about a linear relationship which can be expressed as ây=mx+bâ.
When frameworks argue who is smaller, they can really only compete on two points: the fixed cost of the framework or the variable cost of the application. So either a smaller âmâ or a smaller âbâ.
Ryan Carniato did a nice comparison of different frameworks in his post JavaScript Framework TodoMVC Size Comparison (table replicated below).
For the sake of my argument, the exact numbers arenât important, but the table does a good job of illustrating how, as the application size increases, different frameworks have different slopes (âmâ) and different initial values (âbâ).
The problem is that all frameworks have approximately the same slope. And even if the framework completely compiles away so its âbâ becomes zero, the application dominates the download and execution size. The âbâ kind of doesnât matter for sufficiently large applications.
All of the above lines are âO(n)â. As the application gets bigger, so does the initial bundle size. Applications will continue to get bigger as we continue to build better end-user experiences.
What we need is a new paradigm. We need a framework with a constant load time no matter the application complexity. At first glance, this may sound impossibleâsurely, the initial bundle is proportional to the application complexity. But what if we lazyload code rather than doing it eagerly? I covered why existing frameworks need to eagerly download code in my post, Hydration is pure overhead. Hereâs what weâre looking for instead:
The current status quo is to download and execute all of the code at once. Whatâs needed is a way to sip on the JavaScript as the user is interacting with the site. No interaction, no JavaScript; little interaction, little JavaScript. If thereâs a lot of interaction, we approach the classical frameworks and download most of the code. But the big deal is that we need to shift our mental model from eagerly downloading code at the beginning to lazily downloading code as the user interacts.
Current frameworks already know how to do this to some extent, as they all know how to download more code on route change. Whatâs needed is to extend that paradigm to the interaction level.
In the above image the site is delivered as HTML to the client. Notice that none of the components have the coresponded code loaded. The next image shows which components need to be downloaded and executed on user interectaion. The result is that a lot less code needs to be downloaded and the code which is downloaded is executed later. This offloads the amount of work the CPU has to do on site startup.
The amount of JavaScript we download to the browser is going up every year. The problem is that our site's complexity increases as we deliver more complex end-user experiences that require more code. We have already reached a point where we have too much code in the initial download, and our siteâs startup performance suffers. This is because the frameworks we use are O(n). This is not scalable.
While different frameworks have different slopes in the end, any slope is too much. Instead, we need to lazy load on interaction rather than on initial load. Frameworks already know how to lazy load on route change, we just need to go deeper and do it on interaction as well. This is needed so that our initial load size can be O(1) and we can lazy load code on as needed basis. Itâs the only way we can continue to build even more complex web applications in the future.
Builder.io is a Visual CMS that let's you drag and drop to create content on your site visually, using your components.
Stop drowning in a backlog of requests - build with your whole team instead.