Google cares a lot about startup performance because startup performance influences the user experience. For this reason, Google has built Core-Web-Vital metrics (CWV) that objectively measure the site’s user experience. Google said it would use CWV metrics in its SEO ranking algorithm to encourage the industry to move in the right direction.
Finally, a lot of data shows that startup performance matters for conversions, and Google has compiled a list of studies that show exactly that.
We used to be fast
While the DX of the above is not the best, surprisingly, it produces excellent performance characteristics. To this day, it is how Amazon serves its site.
What the above tweet shows is that serving pages that way, while not the best DX, produces the best UX.
How we got slow
The SPA approach solves a lot of things from the DX perspective. Single language, single mental model, and it is easy enough to teach many developers quickly. So, the SPA took off. Now to be fair, the SPA has one thing going for it: Client-side interactions are fast, but not the startup performance.
At first, SPAs were small, so the startup performance was not too bad. The user would navigate to a page, would see a white screen, and a second later, the application would render. But over time, we kept adding more and more functionality to our applications. Animations, personalization, analytics, CSS in JS, component libraries, etc. Every time we added one of those features, the startup performance would get a bit worse because SPAs require that all of that code be present. Death by a thousand cuts. So, what started as a reasonable compromise quickly turned into an actual problem. Users had to wait too long on the white screen before the site would render.
GAIN INSIGHTS INTO THE DO'S & DON'TS
Performance, Testing, & Security Hacks
The above hacks got on the official name of hydration, and we rebranded the hack into a feature.
The thing to stress is that the DOM created by the original HTML is not needed. If you deleted the DOM, most frameworks would continue to work because, as part of their hydration, they rebuild the DOM anyways.
SSR slows things down
Browsers are very good at rendering HTML, but bigger HTML takes longer to download and renders than just a blank page, so this is not free. Hydration and site prerendering make the time to interaction actually worse, not better! It is only an illusion that things are better because the user has something to look at before they interact with the page.
Current approaches of prerendering HTML with hydration create an uncanny valley. An illusion that the page has loaded and that you can interact with it but attempting to interact produces no result. The page is dead, and there is no clear indication of when the page will become ready. On mobile devices and slow networks, it is not uncommon to see sites take upwards of 30 seconds to be ready for interaction.
Why is hydration needed?
Hydration is a way for a framework to recover information about the application so that the application can become interactive. What information? The application state is the most obvious, but there is much more. Frameworks also need the location of components, component props, event listeners, and reactivity graphs. Without that information, the frameworks can’t function. But that is not something most developers think about as it is an implementation detail of the framework. The frameworks must get that information somehow. Executing the application from beginning to end is how most frameworks collect the information because that is how we initially get the information: We just run the app.
But there is another way. During prerendering of the application on the server, the framework already had full knowledge of the location of components, component props, event listeners, and the reactivity graph. It is just that it was not serialized into HTML. If the framework could serialize the information and send it to the client along with HTML, then the same framework can recover the information on the client without resorting to the re-execution of the application on the client again.
Imagine you have a complex page with lots of components, and one of the components is a counter. Clicking on the counter increments its count. Notice that once the page has been initialized, only the counter handler and the counter rerendering code execute on the client. The fact that there are lots of other components on the page does not matter. Their code is not executed because they are not being interacted with.
If only we could serialize the handler in such a way so that we can recover it without walking the component tree, then we would become resumable. The handler for the counter would be registered as part of server prerendering and would be executed on the client as part of the user interaction. No other code would have to execute.
If we could do that, then the amount of code we execute would be proportional to the user interaction rather than all possible interactions on the page. No code needs to be executed to get the page ready, and when the user finally interacts, the event handler can be directly invoked without pre-processing. This will make the page resumable because the next code to execute is the event handler.
Modern frameworks make heavy use of closures. Closures are everywhere, but especially for event handlers. Initial execution of the application is partly expensive because the framework collects closures and attaches them to the event listeners in the DOM. Getting closures is tricky because they are, by definition, inlined into components. One can’t just import a closure, and even if one could, such closure would not have closed over its contextual variables. Yet getting hold of the closures efficiently is exactly what we need to make resumability work. How exactly this is done is beyond the scope of this article, but it is a key piece of the puzzle.
Serializing Reactivity Graph
The framework needs to be surgical about which components need to be rendered and when to keep the framework from rereading too much. Reactivity is the key. Reactive systems build up a graph that allows the framework to be extremely selective on which components rerender. This keeps the application rendering lean.
Does it matter?
The short answer is: Yes! Google has spent a lot of time collecting data that shows that time to interactive matters! This makes intuitive sense. You are browsing along, and something catches your eye. You click on the link and want to buy the latest shoes! You click the buy button, but it does not do anything. How long do you want to wait, before you give up and tell yourself that you don’t really need those shoes?
But my app built with hydration is fast!
There are a lot of sites demonstrating that you can build a fast site with your favorite technology. And you can! The problem is gradual. You start up fast, and as you add more features, the site becomes a tiny bit slower with each new feature until it is not fast anymore. I am yet to see a production e-commerce site that handles real traffic, and that scores well on Google CVW on mobile.
The question you should be asking is not whether you can build a demonstration site that is fast but whether it will remain fast at scale. Hydration is a cost that is proportional to the size of the application. Will your site remain fast as the size of the application grows?
Resumability has the nice property that its startup cost is constant. No matter how complex your site gets, the startup cost is always zero because there is no startup cost. It is resumable.
Resumability is not new
For almost a decade, Google has had an internal framework called Wiz that powers Google Search and Google Photos, among many other front-facing sites. Wiz is resumable, and it shows. Google Search is fast! As a user, it is not possible for you to interact with Google Search or Photos site before it is ready: It is instant!
eBay uses its own framework, Marko. While not historically resumable, resumability is a new feature that is part of their next release.
And, of course, Builder.io (http://builder.io), a visual CMS platform, is working on Qwik (http://qwik.builder.io). Qwik is the first open-source framework that brings resumability while maintaining great DX for everyone. Builder.io’s goal is to give our customers a competitive advantage through resumability, and as such, Qwik is a core part of our business.
Where are we heading?
We can’t continue building applications the way we have been until now. Yes, we have great DX, and our engineers are productive, but our UX suffers.
The future can’t be more of the same. Companies such as Google, eBay, and Amazon showed that fast sites matter and that it makes business sense! For this reason, I think resumability will become the de facto way to build sites in the future. I don’t know if Qwik will become the preferred way to achieve that, but we hope so.
Once resumability becomes available to everyone, it will start an arms race. Currently, sites are slow, but so is everyone else’s, and few know how to make them fast or have the resources to do so. As soon as building fast sites becomes possible, an arms race will occur as everyone will try to get their sites fast. After all, Google CWV will give a competitive advantage to faster sites, and since building faster sites is no longer prohibitively expensive, companies will adopt it, putting pressure on the competition.
Qwik is not the only framework that is resumable, but it is the first to make resumability its key selling point. The future belongs to resumability because it can significantly increase the conversion rates of the site, which leads to more profit for the business. We think resumability will start an arms race as a faster site will create a strong competitive advantage and force other businesses to implement the same technology to stay competitive.