
Learn web development, they said; it’ll be easy, they said. Calling web development easy is the understatement of the century. You’ll need to choose from millions of Frameworks and at least ten different rendering strategies or architectures when building a web app. In today’s blog, we’ll look at all 10 of them along with the Frameworks that support them so you can make the right decision as the CTO of your project.
First of all, though, what is a rendering pattern? Well, rendering is the process of turning data and code into HTML that the end user can see. This can be done on the server or in the browser. It can be done all at once or partially. These all have trade-offs in user experience, performance, and developer experience.
The original and most basic rendering paradigm is a Static Website. You put together all of your web pages in advance in this rendering paradigm. Then upload them as static files to a storage bucket somewhere in the cloud and point a domain name to them. This works excellently even in today’s world. Frameworks like Hugo, 11ty, and Jekyll can help you build them programmatically. The drawback is that they are not great for websites where the data changes often. So it’s only suitable for basic websites that don’t require a ton of interactivity or dynamic data.
Eventually, websites needed to be more dynamic. And that brought us Multi-Page Applications — where the HTML and data are put together dynamically on a server whenever a request comes in from a browser. This means the website’s appearance can change whenever the underlying data changes. Many of the biggest web apps today still use this approach. For example, if you go to amazon.com, notice how every time you click on a link, you get a new dynamically generated page from their servers. In addition, there are many popular Frameworks for building multi-page apps like Ruby on Rails, Django, and Laravel, as well as Content Management Systems like WordPress.
This approach worked great until the iPhone came out. Then people realized that having this full page reload on every URL feels clunky compared to the super smooth iPhone apps. That’s why approximately in 2010, we saw the rise of the Single Page Application with frameworks like AngularJS and React a few years later. In the SPA paradigm, all the UI rendering happens in the browser. You start with one HTML page as a shell, then execute JavaScript to render the UI and fetch any required data with an additional HTTP request. Now even though it’s just a single page, it can still have multiple routes. These routes don’t point to a server. JavaScript updates them in the browser. This has the massive advantage of feeling instantaneous to the end user, unlike a Multi-Page Application that might take at least a few hundred milliseconds or more to render the page. But there are some significant disadvantages. One is that it requires a large JavaScript bundle, which can slow the initial page load. And two, because it only renders a shell, search engines, even today, cannot understand any of the content on the dynamic routes. And that’s a no-go if you need good SEO or want people to share your content on social media.
A few years later, it was time for a new framework. Something that could render HTML and data on the server or the initial page load. Then hydrate to client-side JavaScript afterward. We call this SSR today, but the general idea is that the initial request goes to a server and renders everything dynamically. Then after that initial page load, JavaScript takes over to give you the app-like Single Page Application experience. This best-of-both-worlds approach is used by frameworks like NextJS, Nuxt, SvelteKit, and so on, often referred to as meta frameworks. This is likely the most popular rendering strategy today, but there are still some drawbacks. One drawback is that you need an actual server, which costs money.
A slight variation on SSR is SSG or Static Site Generation. In this paradigm, you render all of your HTML in advance. Then upload it to a static host like a storage bucket. But like SSR, it will hydrate to JavaScript after the initial page load. Websites like these are called Jamstack sites and are typically built by the same meta frameworks like NextJS, Nuxt, and SvelteKit. You get the simplicity and low-cost hosting of a Static Website with the app-like experience of a SPA. The only bad thing is you must redeploy your site whenever the data changes.
And that’s why they invented ISR or Incremental Static Regeneration. This paradigm started in NextJS, and the idea is that you deploy a static site. But you rebuild individual pages on the fly on your server when the cache is invalidated. Generally, with a static site, you can cache everything permanently on a CDN, making it extremely fast. With ISR, the cache can be invalidated based on certain rules, like a specific amount of time. When that happens, the pages will be rebuilt. This allows you to handle dynamic data without needing an actual server deployment like you would with SSR. You get the best of both worlds between SSG and SSR, but the drawback is that it’s more complex to set up on your own, so you’ll likely need to find a host like Vercel that supports it out of the box.
There is another problem we have yet to discuss with any framework that uses hydration. The app might feel frozen on the initial page load while the JavaScript is still executing to take over the rendering process. To solve this problem, we have Partial Hydration. On a large website, JavaScript may have much to do with things that aren’t visible to the end user. You may have the world’s most unique and highly interactive footer, but it blows up the JavaScript call stack. With Partial Hydration, you can first render the components at the top of the page and then wait until the user scrolls down before making that component interactive. Many tools today support code splitting to break your apps into smaller chunks to facilitate lazy loading patterns like this.
But it may be possible to render even more efficiently with the island’s architecture. Usually, when hydrating, JavaScript takes over the entire page. But that could be more efficient because many components are static and non-interactive. With Islands, you start with static HTML and only use JavaScript to hydrate interactive components. This gives you “Islands of Interactivity.” Frameworks like Astro facilitate this pattern. What’s cool about it is that you may have a page that’s not interactive at all. In this case, no JavaScript is ever shipped to the client even though you built the UI with a JavaScript framework like react.
Yet another way to address inefficient hydration is a paradigm called streaming SSR. It is supported in frameworks like NextJs 13 with the app directory thanks to building blocks like react server components. It allows you to render server-side content concurrently in multiple chunks instead of all at once. Ultimately this means the UI becomes interactive faster and feels more performant to the end user. But what if we could get rid of hydration altogether? It seems to be the source of many problems.
Well, that’s where Resumability comes in, a new rendering paradigm pioneered by the Qwik framework. It takes an interesting approach where a website and all its data, including JavaScript event listeners, are serialized into HTML. Then the actual JavaScript code is broken into tons of tiny chunks. That means the initial page load is always static HTML. No hydration is needed. Any JavaScript required for interactivity is lazy-loaded in the background.
And with that, we’ve looked at ten different rendering patterns on the web. I’m sure many more will be invented in the coming years, but hopefully, you can go and build the website of your dreams. Thanks for reading.
