Photo by tiarescott on Flickr
As discussed in the previous article in this series, hydration initializes an application by adding interactivity to server-rendered HTML. Doing so can cause serious performance problems due to the entire application needing to render before becoming interactive; long tasks, UI stutter, and even pauses can be consequences of this heavy-handed initialization strategy. There are two effective ways to tackle this problem: (1) do less work when hydrating by skipping the portions of the DOM that will never be interactive (a.k.a. “partial hydration”) or (2) do hydration at some point in the future (a.k.a. “progressive hydration”); only the former will be the focus of this article, then the latter will be covered in part 3 of this series.
Where did the modern “islands” naming come from? The idea of “component islands” was named by Katie Sylor-Miller – frontend architect at Etsy – back in 2019 and expanded upon by Preact creator Jason Miller in his blog post entitled Islands Architecture. Within it, he explains how “islands” can be thought of like independent single page applications wherein top-down rendering is not required for the full page output to be built. Rather, each island is an isolated unit, so any potential performance problems in one “application” do not affect any others. A side effect of combining many single page apps (SPAs) onto a single page is that client side routing is lost because they all cannot control the browser’s URL, thus the application must be a multi-page app (MPA) with full-page reloads; stay tuned for part 5 of this series for how server components help solve that problem. He continues to explain that because the full HTML is returned to the browser, SEO and accessibility benefit because web crawlers and assistive technologies inherently understand the semantics of static HTML better than a dynamically changing DOM. Navigating with
- Nav Bar
- Shopping Cart
- Product Image
- Buy Now Button
- Product Description
- Product Reviews
- Related Products
Partial hydration should include only interactive components and their children. Specifically, draw a colored line around only the interactive components on the page; the diagram above shows exactly this, and if you squint a little, they look like islands of interactivity hence their name. Now only 3 components’ code should be sent including:
- Shopping Cart
- Buy Now Button
- Product Reviews
Unfortunately partial hydration has some drawbacks as well. The first and most obvious is requiring full-page reloads during navigation; server components are effectively persistent islands which can mitigate this and will be covered in part 5 of this article series. Traditionally, partial hydration was very difficult to set up. You effectively needed to design a build process that dynamically created multiple render roots for multiple component trees and the ability to pass props to each one independently in addition to being able to share state between them. A good example of this is Markus Oberlehner’s terrific overview of this process in his blog post entitled Building Partially Hydrated, Progressively Enhanced Static Websites with Isomorphic Preact and Eleventy. The process he describes is very manual and was written before the advent of modern islands solutions included in frameworks like Astro. Additionally, state sharing between islands is made more complex than a traditional context-based design because there is no shared component root. Luckily, however, signals and signal-like libraries have been developed that can tackle this problem very efficiently and effectively; some libraries such as the Astro-recommended Nano Stores are less than 1 kB! Thus, whether this is truly a problem is a matter of perspective.
After all this promise of performance improvement, how can partial hydration be used today? The easiest and most flexible option is Astro because you can not only choose from a variety of frameworks for your islands like React, Preact, Vue, and SolidJS, but you can even mix-and-match different frameworks in islands on the same page! It even supports deployment adapters for serverless and edge rendering platforms too with only a few line changes necessary in your config file. If you’re a fan of Deno, the Fresh framework has great support for islands as well. The most-performant but least well-known option is Marko, especially the upcoming Marko 6 release whose compiler optimizations and support for resumability and fine-grained reactivity will be truly something special.
I hope you enjoyed this overview of the islands architecture. If you have any questions or feedback about this topic or any others, please share your thoughts with me on Twitter. I would certainly enjoy hearing from you! And be sure to check out Babbel’s engineering team on Twitter to learn more about what’s going on across the department. Stay hydrated!