Monolithic applications may not be all the buzz today, but many (WordPress, Ruby on Rails, Laravel, etc.) are alive, active, and still heavily used.
In fact, one major benefit to not being all the buzz is that “the buzz” has evolved far enough in the last several years that many modern patterns can be applied to more traditional means of building websites and applications.
Here, we’re going to look at islands architecture. It’s a paradigm that has been talked about for a couple years, but has been getting more attention recently. Similar paradigms are used in new features just released in Next.js 13 (one of the most popular modern frameworks), hinting that this type of pattern has enough support to evolve into the mainstream.
Our goal here is to explore how we can take advantage of the benefits of islands architecture when working with a monolithic application. Let’s first look at determining exactly what islands architecture is to better know if it’s the right move for your application.
To understand how islands work, let’s first look at an overly-simplified history of rendering HTML on the web:
At first glance (and without much nuance) this history seems to hint that we’re back where we started, almost two decades later.
DHH on Twitter: “The pendulum is finally swinging back, and with the force of a wrecking ball. May the towers of needless complexity built in the past decade be smashed to smithereens 💥🔨 https://t.co/PPGUB2U6Af / Twitter”
The pendulum is finally swinging back, and with the force of a wrecking ball. May the towers of needless complexity built in the past decade be smashed to smithereens 💥🔨 https://t.co/PPGUB2U6Af
The irony of the popularity in rendering via the server, then the client, then the server again is obvious. But it’s not that simple. Each revolution has been an evolution in creating a better developer experience for the web and, frankly, to make building for the web more accessible to more people.
In the years since Next.js has gained popularity, countless tools have emerged to try to solve how find the perfect balance of performance and developer experience.
The common pattern that has emerged generally centers around what we call progressive hydration. With progressive hydration, HTML is sent to the browser from the server. This can be via SSR (built on request) or SSG (prebuilt).
This paradigm is what Next.js and others use to enable developers to use UI frameworks like React to build the entire UI with components, and separately choose the most effective means for delivering that content to the browser.
There are some great introductory posts to islands on these sites:
Before we move on, it’s important to recognize that we’re not at the end. New optimizations and patterns are constantly emerging. The recent release of Next 13 using React Server Components along with Shopify acquiring Remix are two stories that are continuing to find new ways to optimize that balance between developer and user experience.
There are a number of benefits to the islands approach, but most are contextualized with improving upon existing frameworks that ship dependencies that could be handled on the server. For small and/or mostly static applications, it absolutely makes sense. It’s a great choice.
Instead, let’s consider what I find to be the two primary benefits in islands versus traditional SSR monolithic frameworks:
You can take advantage of islands architecture in your monolithic application in a few different ways. And they don’t necessarily mean migrating. It’s about changing your way of thinking about the interactivity on your site.
You may have heard of web components. They seemed cool for a minute or two. Well…they’re back! And that’s in large part thanks to ideas like islands architecture.
The 11ty team also has another project in the works called is-land, a web component that hydrates itself based on some specified event (for example, when it appears in the viewport). is-land is a single script that is also meant to be framework agnostic, although it works best with 11ty. This is worth considering in addition to WebC, or even on its own with your custom implementation of rendering web components.
You may not want to use these frameworks or libraries directly, but you can use them to develop a solution that would better suit you and your tooling.
As these UI frameworks were gaining incredible popularity, the folks over at Basecamp (creators of Ruby on Rails) developed Hotwire, a tool for wrapping server-side actions in isolated sections of the page without reloading the page. It simply gets the resulting HTML back from the server response and replaces only that portion of the page.
There may be a tool like Hotwire available for the framework you’re using.
In other words, this approach only gets you part of the way to a true islands approach to your frontend code.
And last, there’s always the nuclear option: rebuild!
If you want the benefit of modern web patterns, but the previous ideas feel like too much customization or effort, it may be time to upgrade your frontend.
Of course, it always feels like a lot when we’re talking about upgrading an entire application. But it doesn’t have to be. You can do this one piece (page, route, etc.) at a time, making it a gradual migration, or a strangler fig application.
The way that many migrate from monolith to a more composable approach is to build your front and back ends separately, which is likely an easier path because you won’t have to move your data. Instead, your current application slowly becomes an API-only app, while you spin frontend pages off into a new application.
As you can tell, this isn’t a one-size-fits-all sort of migration. There are many types and sizes of monolithic applications today. And there are many ways in which you can achieve the benefits of an islands-like approach to your front-end code.
If nothing sounded immediately obvious or beneficial, I’d suggest trying a small-scale implementation of a few approaches within your current system. If something feels right, you take it a little farther until you have the confidence that it can scale to serve your entire application. Or you move on to try the next thing.
Install LogRocket via npm or script tag.
LogRocket.init() must be called client-side, not
Vite is a versatile, fast, lightweight build tool with an exceptional DX. Let’s explore when and why you should adopt Vite in your projects.
Explore advanced capabilities for content sharing with the
navigator.share API, including dynamic content sharing, custom share targets, and batch sharing.
We spoke with Chas to get his insights on building technology and internal processes for companies that are scaling quickly.
Cypress is one of today’s foremost tools for testing web applications. Let’s explore when and why you should adopt Cypress in your projects.