We are no stranger to building decoupled applications, but until recently we have reserved this approach for highly interactive projects or projects that need to serve multiple channels/platforms. With developments in server-side rendering (SSR) using Next.js, however, we are looking to roll this out for even our most straightforward upcoming projects.
What is headless?
Instead of a traditional “monolithic” architecture in which everything is contained within the same system, a headless (or decoupled) project separates out the backend content and the client-side frontend rendering. The backend provides data in the form of an API, and the frontend consumes the data to be rendered in the browser. Typically the frontend will leverage a javascript framework such as Angular, React, or Vue, opening up many possibilities on how to display content.
The benefits
The main upsides of going headless are as follows:
-
Ability to serve multiple channels/platforms: one backend database could provide data to a website and multiple other applications.
-
Flexibility: Separating the front end means we have more freedom of choice on how to build pages, using cutting-edge technologies.
-
Testability: Since it consumes an external API, the frontend can be more easily tested in a CI pipeline.
-
Component drove: perfectly complementing our design system approach, our frontend developers can build UI components in isolation without having to concern themselves with the backend logic.
The catches
However, there can be some downsides if not dealt with:
-
Added complexity: whether we are using REST or GraphQL to fetch data, it adds a layer of complexity compared to a monolithic application which would typically have its own built-in templating system.
-
Added complexity (part 2): Much functionality you would be familiar with in a monolithic app would have to be “rebuilt” e.g. routing, internationalization
-
Performance: Since more things are going on, with multiple data fetching requests, this can hurt site speed. Caching a dynamic application without SSR could be a very difficult task.
-
Search Engine Optimisation: Before SSR, Angular/React applications could suffer from SEO implications; since the only output sent to the browser is javascript Google can have trouble indexing and crawling the site.
Why and how we use Next.js
Next.js is a framework built on top of the popular React library, which aims to solve some of the issues highlighted earlier:
1 - Static / Server-Side Rendering
Unlike traditional React apps, Next.js will build and cache static HTML files from the frontend code and the backend data. Using Incremental Static Regeneration (ISR) these pages are rebuilt periodically so that the content stays up to date. For pages that should always be dynamic and therefore not be cached, this is also possible, and can still be server-side rendered so Google can index and crawl them easily.
2 - Performance
Static generation means pages load lightning-fast. If this isn’t enough, Nextjs has a multitude of features to help increase your page speed, including:
-
Automatic image optimization
-
Background prefetching of pages
-
Automatic code splitting ensures only the relevant javascript and CSS is loaded on each page
3 - Complexity
Next.js solves many cases of “reinventing the wheel” with built-in features such as file-system-based routing and internationalization, helping to decrease the front-end development time compared to a standard React app.
But there still remained one problem: the data-fetching complexity roadblock was the one thing that Next.js can’t really help us with, and so we needed to figure this out ourselves. This was always holding us back from going “full headless” since the amount of work involved in fetching and organizing data for a content-managed site seemed too much work for anything but the most complex needs.
One endpoint to rule them all
After exploring all of Drupal’s headless options (REST, JSON: API, and GraphQL) we found that none of the offerings really catered to our needs of how we build sites. What we really wanted was to send a request to an API with a URL path and for the API to return all the data required to render the page. This is why we went to the drawing board and came out with what we dubbed “one endpoint to rule them all”.
In simple terms, the custom Drupal endpoint looks up the URL path, fetches the associated content, and iterates through the fields, formatting the data into a readable format. We define how fields are formatted using YAML files, which also accommodate nested references, and a hook system so that other modules can alter the output if needed.
The complexity has now been reduced to a minimum, so we can spend more time on building and less time on boilerplate and configuring.
Conclusion
We found that Next.js in combination with our custom Drupal workflow works incredibly well, and has simplified the process enough that we are confident to use this approach on our future projects, big or small, complex or simple.
See our Next.js + Drupal project Cayan Education