Leveraging the Island Architecture in Jahia CMS

islands architecture schema.svg
Jahia is the only DXP that truly empowers you to deliver personalized journeys powered by customer data Learn how here

Building an interactive website should never compromise performance. Frontend architecture is evolving to meet the demands of an ever immersive web experience without sacrificing decade-long performance standards. Island Architecture is a pioneering approach that allows developers to create highly interactive websites while maintaining optimal performance.

What is Island Architecture?

Let's go back in time to understand what lead to the invention of Island Architecture.

In the early days of the web, pages were static, rendered on the server by frameworks and languages like PHP, Ruby on Rails, or Java. The application produces HTML and CSS, and interactivity was limited to links and forms. This approach is known as Server-Side Rendering (SSR).

While this approach was (and still is) effective for many use cases, it offers a limited range of interactions and requires to reload the page for even minor changes. This led to the emergence of its polar opposite: Single Page Applications (SPA). SPAs, powered by JavaScript frameworks like React, Vue, or Svelte, allow developers to create end-to-end web applications with rich interactivity without the need for full page reloads.

However, since SPAs can only run in the browser, they usually have poor initial loading performance and are not SEO-friendly, which can be detrimental to user experience and search engine rankings.

Coined by Katie Sylor-Miller, Island Architecture is a new approach that combines the best of both worlds: the performance of static sites and the interactivity of SPAs.

A website with "islands" of interactivity is first rendered by the server as a static HTML page. When the page loads, JavaScript is used to hydrate (i.e. make interactive) only the parts of the page that need it, leaving the rest of the page as static HTML. 

islands architecture schema.svg

In this example, the page is mostly static, with the exception of the <Navigation /> and <Video /> components, which are the islands of interactivity of the page. After the initial page load, JavaScript is used to hydrate these components, making them interactive without affecting the rest of the page.

Hydration is the process of turning static HTML elements into interactive components by attaching event listeners and re-rendering them when their state changes. Once hydrated, the Lifecycle of React starts, and the components behave like a regular React components. Island Architecture is often referred to as Partial Hydration, as opposed to the full-page hydration of SPAs and applications with Client-Side Rendering (CSR).

As all new approaches, Island Architecture presents its own set of challenges for developers. At Jahia, we are committed to making it easy to build interactive websites with optimal performance.

Why Island Architecture?

Server-side rendering is unparalleled in terms of performance and SEO. You cannot beat the performance of shipping a complete HTML page to the browser.

This is why Jahia websites are rendered on the server by default. The Jahia rendering engine composes React and/or JSP components into a static HTML page, which is then sent to the browser. This approach ensures that the initial page load is fast and SEO-friendly, and with zero bytes of JavaScript by default.

When using React, Jahia supports three different rendering strategies:

  • Server-Side Rendering (SSR): the component is rendered on the server and sent to the browser as a static HTML page. This is the default rendering strategy in Jahia, and it is not interactive. Most CMS pages fall into this category: blog articles, landing pages, search results pages, etc. SSR is also the simplest choice to ensure that the user has the proper authorization to access the page.
  • Island Architecture (or Partial Hydration): the component is rendered on the server as a static HTML page, and then hydrated on the client to make it interactive. This sends both HTML and JavaScript to the browser. For instance, a navigation menu can be rendered as static HTML then enhanced with event listeners to make it interactive. A search input can suggest terms as the user types. Or an image gallery can display a lightbox when an image is clicked. These interactions are not critical to the page, but they enhance the user experience.
  • Client-Side Rendering (CSR): the component is only rendered on the client, which means that the browser receives only JavaScript, and no HTML. This approach should be used sparingly, and reserved for non-critical components that would not work without JavaScript. This category includes advertisements, animations, feedback forms, etc. Ensuring that your website works for users without JavaScript is called Progressive Enhancement, and it's one of the many aspects of Accessibility. 

Island Architecture is the only approach that is both performant (fast initial load) and interactive. How is it different from SSR with a bit of jQuery, you may ask? The key difference is that, when building Islands, you use the exact same React components on the server and the client. Having a single-language codebase will be easier to maintain in the long run.

Using Island Architecture in Jahia

We strive to offer an optimal Developer Experience (DX) when using Jahia. The APIs we provide to implement the Island Architecture are designed to be simple and intuitive.

Here is what implementing the Island Architecture in Jahia looks like:

import { HydrateInBrowser, jahiaComponent } from '@jahia/javascript-modules-library';
import Button from './Button.client.jsx';

// Declare a view for `example:card` nodes
jahiaComponent(
  {
    componentType: 'view',
    nodeType: 'example:card',
  },
  ({ title }) => (
    // These <article> and <h1> are server-rendered
    <article>
      <h1>{title}</h1>
      {/* This <Button> is server-rendered then hydrated in the browser */}
      <HydrateInBrowser child={Button} />
    </article>
  )
);

In Jahia, all view components are server-rendered. Partial hydration and Client-Side Rendering (CSR) are implemented using Jahia-provided components: HydrateInBrowser for partial hydration and RenderInBrowser for CSR.

These two special components take a child prop, which is the component to be hydrated or rendered in the browser.

The <Button /> component is a regular React component:

import { useState } from 'react';

export default function Button() {
  const [count, setCount] = useState(0);

  // Clicking this button will increment the count
  return (
    <button type="button" onClick={() => setCount(count + 1)}>
      {count} clicks
    </button>
  );
}

The component is then transformed by our Vite plugin to minify the JS code sent to the browser.

Advanced Usage: Partial Hydration

We understand that not all use cases are as simple as a counter, and we went further than the Island Architecture paradigm.

In all the examples above, the island of interactivity is a leaf of your component tree, meaning that it is not a parent of any other content. This raises the question:

How do you interleave interactive components with static content? 

diagram of an accordion component.svg

An example of such use case is an <Accordion /> component: it is interactive but its content is rendered on the server.

Jahia APIs support the special React children prop. Here is how the <Accordion /> component can be implemented:

import { useState } from 'react';

// `title` is a regular string prop
// `children` is the special prop that contains the content of the accordion
export default function Accordion({ title, children }) {
  const [open, setOpen] = useState(false);

  return (
    <article>
      <button type="button" onClick={() => setOpen(!open)}>
        {title}
      </button>
      <div hidden={!open}>
        {/* The children are rendered on the server, but not hydrated in the browser */}
        {children}
      </div>
    </article>
  );
}

This component is then instantiated using HydrateInBrowser:

import { HydrateInBrowser, jahiaComponent } from '@jahia/javascript-modules-library';
import Accordion from './Accordion.client.jsx';

jahiaComponent(
  {
    componentType: 'view',
    nodeType: 'example:accordion',
  },
  ({ title }) => (
    <HydrateInBrowser child={Accordion} props={{ title }}>
      {/* This content populates the `children` prop */}
      <p>I'm rendered on the server!</p>
    </HydrateInBrowser>
  )
);

<Accordion /> is no longer the leaf of the component tree: it can take server-rendered content as its `children` prop, which will not be hydrated in the browser.

There is also a regular title prop on the <Accordion /> component, which is provided through the props prop of HydrateInBrowser. This allows you to pass any number of props to the interactive component.

Try It Out!

Jahia CMS is open-source and free to try. If you want to try our implementation of the Island Architecture in detail, please refer to our documentation to get started with Jahia.

 Creating a new module with Jahia is as simple as running a command:

npm init @jahia/module@latest <module-name>

The CLI will guide you through the process of starting a new Jahia instance locally and uploading your module to it.

Conclusion

We hope this article has helped you understand the concept of Island Architecture and how it can be used to build highly interactive websites with optimal performance in Jahia.

If this article leaves you on your thirst for technical details, we have another article that goes deeper into our implementation of the Island Architecture: Hydrating React Components in a Java CMS.

Back