But the thing you probably should be paying attention to is that the frameworks themselves have been investing heavily into this area for the past 2 years. There is a reason why we've been waiting for Suspense in React, or we see blog stories about Island's Architecture. Why Svelte and Vue have been pulling meta-framework type projects under their core's umbrella. This is the thing everyone is chasing after.
So I want to take some time today to fill in the gaps, talk about the underlying technology, and overall paint a better picture of what is going on.
Why server render at all? For some of you, this might be obvious. But it wasn't for me.
But these are not new. So, let's take a look at what I believe are the bigger motivators for the current conversation.
It all boils down to the fact that nothing happens in the browser until it receives the HTML page back. It is only after starting to receive the HTML that other assets are requested.
Here is the rub. This is further compounded by the desire to keep the bundle size small. Code splitting is incredibly powerful and easy to do on route boundaries, but a naive implementation ends up like this:
Four consecutive round trips! The main bundle doesn't know what page chunk to request until it executes, and it takes loading and executing that chunk before it knows what async data to request.
Knowing the route you are on lets the server render right into the page the assets you will need even if code split. You can add
<link rel="modulepreload" /> tags or headers that will start loading your modules before the initial bundle even parses and executes.
Additionally, it can start the async data loading immediately on receiving the request on the server and serialize the data back into the page. So while we can't completely remove the browser waterfalls we can reduce them to 1. However, a naive approach here actually delays the initial response of the HTML page. So it isn't a clean victory.
In fact there is a lot more we can do here that I will cover in a follow-up article.
But invalidating out of date service workers and cached assets can be a whole other sort of issue. Stale while re-validating can go a long way for certain types of applications. Sites that need to be up to date might not opt for this and use caches they have more control over.
So the takeaway on this whole topic of performance/size is that the client alone has many techniques to mitigate most things other than that first load of fresh content. That will always be constrained by the speed of the network. But as our applications scale, without due consideration, it is easy for our SPA performance to degrade and a naive application of best practices only introduces other potential performance bottlenecks.
Server rendering can relieve a couple of the important ones if the initial load is important to our sites and applications.
These tools may have been developed with interactive web applications in mind, but there is a much larger set of potential users to tap into that appear to actively be looking to these frameworks for their simpler sites.
This is a really compelling problem. Especially when you consider that the coordination between Client and Server can be really complicated to do efficiently manually. Whenever something is used outside of its original parameters it takes some special consideration.
The fundamental thing client-side libraries have been solving is state management. It's the whole reason MVC architectures have not been the right match for the client. Something needs to be maintaining the state. MVC with its singleton controllers is wonderful for stateless things like RESTful APIs but needs special mechanisms to handle the persistence of non-model data. Stateful clients and stateless servers mean reloading the page is not acceptable.
The challenge for server frameworks is even with mechanisms like Hotwire for partial updates, it alone doesn't make the client part of the equation any less complicated. You can ignore it is a thing, and if your needs are meager this can suffice. Otherwise, you end up doing a lot of the same work anyway. This leads to essentially maintaining two applications.
Well, be prepared to hear about this a lot more. This has been going on for about 2 years now, but these projects are finally starting to emerge to a point people feel comfortable talking about it. This has taken time because it's a fundamental shift. While there are Next's and Nuxt's of the world the core libraries haven't been optimized for these cases.
Short of really eBay's Marko we haven't seen to date the sort of sophistication you'd expect from these sort of solutions. But that is all changing. React Server Components are one example. You better believe Vue, Preact, Svelte, etc... have all been working on their own solutions in this space.
For more information on optimizations being implemented check out: