Everyone seems to have an opinion on this topic of late. You may have seen: Second-guessing the modern web By Tom MacWright.
But even I recognize something is disjointed here. However, the call to return to a simpler time is also naive. I want talk a bit about motivations and look at what is actively being developed by the top libraries in addressing these concerns. And that is the thing. Everyone is taking this very seriously and has been for at least the past year.
Since the dawn of the web there has been a desire for more interactivity. While most things could be simple sites, there was always the demand. It took a long time for us to get to a point where the web could use it's own tools to deliver this experience, which had previously been reserved for Applets, Flash, Silverlight.. etc. What might have started as focused media, like video players and interactive panels eventually grew into Native app envy as touchscreens became pervasive in the mid 2000s.
Even then we choose to categorize these use cases. And for good reason. They are built of the same building blocks but they use drastically different technologies and seemingly have different requirements. But at a certain point you have to wonder why do these need to be different things. At this point we've walked all over the spectrum of client vs server responsibility. If these things aren't all that different, why don't we have a single solution?
Yes. But I think ultimately that's ok. Sometimes it takes acknowledging the problem is significant to be willing to go places you wouldn't before. And over time we can refine things haven't been explored as thoroughly. Google IO 2019 was what personally finally clued me in. I always loved watching their talks on Polymer or the future of Web Components, PWA's etc.. but this year it was crickets on those topics. Everything was about supporting Frameworks like Next.js and focus on how Angular was addressing things. And using small libraries like Preact for examples. The shift from the past couple years was jarring.
So why would Google and the Chrome team want you to use Next.js? That's an article in its own right. Reading between the lines: unmanaged they feel the current trend in frontend SPA's will affect their reach into the global market. Chrome wants the web to win more than anyone. How can that happen when the average experience is so much worse than native for these low power devices and limited networks? They are actively working on reducing bundle size in Webpack and improving network latency and parsing. They aren't just building the platform anymore. This is vital to their success. And while they are taking many different tacts they are still betting on SSR, which says a lot.
This is so important that a client-side guy like myself is even in this. I never thought a year ago that the vast majority of my R&D effort in 2020 would be on SSR. And if you look at the big players there is a trend right now, and they've been going at it even longer. The teams making the core libraries are spending time on this not just the community. Without a doubt this is why React Suspense isn't fully released yet. So let's get a bird's eye view of the type of things being worked on.
I want to start here because this has been the big push from the more typical server rendered crowd. The idea here is you server render your pages as normal and then can inject them in a seamless way.
Turbolinks are a way of doing full page replacement with server rendered HTML. Instead of reloading the whole page, you request the HTML for the next page and replace it in place.
Mind you these approaches don't really address interactivity, but just the shortcomings of multi-page web applications. However, some traditionally client side approaches have been looking a similar idea of having the routing be purely server side to save from having to ship it to the client. The routing is the one piece on the client tends to wire the whole application together and can be a cause of bloat in initial JS packages. It's the part you don't get to code split.
The idea here is to not load all the JS immediately(progressive) or at all(partial) so that the page only loads the JS it needs at the time. Libraries identify Components that are stateless or you don't need when the page loads and then hydrates them as needed. This usually is accompanied with techniques to capture event handlers before the section of the page has hydrated so that it can replay them after hydration to offer consistency even if not immediately responsive. This is an area that is often more complicated than it seems. And time will only tell how effective this will be at diminishing the "uncanny valley", or the time between First Contentful Paint and Time to Interactive. Most modern client side libraries that support SSR have been looking into techniques of this nature although it alone might not make a big enough difference.
React/Preact etc.. have been actively developing in this area. But it has proven challenging for libraries that have so much dynamic potential. It is vital to establish blocks in the templates to limit complexity and ensure consistency. This goes beyond individual Components. You can see how this informs things like Suspense. But it is clear the React team is taking UX/DX under consideration above all else, as suspend on read is an amazing pattern for the client but makes it very difficult to predict suspension ahead of time on the server, which likely will lead to patterns where Suspense components are the boundaries. When considering loading waterfalls, something we take for granted on the client, it actually complicates things here.
Interestingly enough there is at least one library that has already accomplished both streaming and partial hydration years ago. EBay's eCommerce platform had a need for this sort of performance out the gate if it was to ever offer the right level of interactivity and quick page loads required to replace its Java backend. Marko.js has been doing the above for about 5 years now with significantly more performant SSR. So don't give up hope on other client libraries getting there soon. It seems they are now poised to improve their client-side of the equation. So I'm interested to see who completes the story first.
Don't expect some big regression into the past to happen. I think we will see continual improvements in this area for the next several years and possibly even convergence. Traditional server templating techniques like Marko finding their place on the client, as readily as React finding its place on the server. For people who don't need all that there are Portals. In the same way there is Static Site Generation for people who don't need SSR. Could Portals solve SSG Hydration performance issues by removing routing from the equation for more static sites? Maybe. Will streaming be more prevalent in how we load data in the future? Likely. It's like the solutions already have their counterpart and we are just waiting to see how they can best be put together.
Client Side only implementations are also not as dire as sometimes depicted. While the average bundle size has been going up, libraries have made great improvements in size and even performance and memory usage the last several years. I've made it my mission the last couple years to show the absolute potential of client side only approaches (See RealWorld Demo Comparison). Things don't have to be the way they've been and they are always improving.