Drupal as a headless CMS: how to leverage the benefits?
The use of a "headless" or "decoupled" CMS is gaining momentum. With the developments in front-end frameworks such as React, VueJS and Angular, and the growing need to be able to share content on different platforms, the separation of content and presentation is a logical step. As Drupal specialists, we were looking for an interpretation that builds on our current solutions. In this article, we share our findings and present a setup that might work for you as well.
A headless CMS, when to use it and when not to use it?
If branding and user experience are priorities on your website, then a headless CMS gives much more flexibility. It also makes the move to a web application much easier and therefore more future-proof.
However, for large projects that rely on a lot of functionality (offered by Drupal), a headless CMS is often impractical and financially unfeasible: all functionality must then be re-implemented. Thereby, Drupal is optimized for SEO and loading speed, among other things. In the headless setup, however, this is still in its infancy. For sites where speed and findability are paramount, Drupal is therefore still the better choice for the time being.
That does not alter the fact that we find the potential of a headless CMS setup very promising and we expect to use it more and more. In the coming period we will invest in the step-by-step migration of functional components to increase applicability.
Existing solutions
There are many solutions for headless websites: both SaaS solutions (e.g. Contentful and Netlify) and open source software (e.g. Strapi). Well-known systems such as Drupal, Wordpress and Sitecore also have solutions for headless websites. For us, a SaaS solution is usually not desirable; due to the limitations of these systems, we are much less flexible and stuck with ongoing contracts. Therefore, our preference is self-hosted and open source.
Another category is static generators: systems that generate a static version of the website with dynamic content that can be managed from a CMS or from code. Big advantage is that the setup is simple and the website is super fast because it is all static data. However, sites with completely static data offer almost no functionality: so you will have to develop it yourself. However, we are looking for a setup where we can also add components such as search, forms and comments.
Our solution
Drupal as a CMS
Drupal is one of the better known and larger open source content management systems and is optimized for both simple and complex content structures. It offers out-of-the-box solutions to most issues and can be extended as desired with the many modules developed and supported by its community of developers.
It was obvious to look for what Drupal's role is (and can be) in a headless environment. Although the new techniques in Drupal 8, including the powerful Twig template engine, offer new possibilities, this setup still feels a bit "old. Great strides have been made in the frontend area; now it's time to look at the next steps.
For more than 10 years, we have been using Drupal for content-driven projects. Since Drupal 8, the core of the system is slowly shifting to an API-first setup: all content created in Drupal is directly available through an API. This makes it well suited for systems where separation of presentation and content are desirable.
React as a frontend
For almost all mobile web applications, and in some cases React Native for native mobile apps, we have been using React for a long time. As such, it is currently by far the most widely used front-end framework. React is "component-based" which means that elements for a website or app act as building elements that can function independently of each other. Reducing interdependencies reduces complexity and makes components more reusable. This made it a logical choice to set up the front end entirely in React.
React, Redux and Immutable
For a clear separation between form and content, we choose the state manager Redux. This state contains all the information that determines what the app displays at any given time. To achieve separation, a state should not be directly modifiable. In Redux, it must be through the execution of actions, which are picked up by reducers that modify the state where the store is responsible for holding the state. To ensure that the state is not directly modifiable, we use Immutable; a library that makes the data in the state non-modifiable.
Rest API, JSON:API and GraphQL
A decoupled setup needs a communication layer in addition to a frontend and backend: the API. Drupal 8 comes standard with a Rest API module that makes all content available. This API is clear and in principle fully meets our needs. However, the data is rather large and cumbersome and is completely separated. This causes us to have to load a large amount of data and make separate calls for everything. For example, take a page where there are two references: one taxonomy term and one image. This causes us to have to make three separate calls: one for the page, then one for the taxonomy term and one for the file.
The JSON:API standard was created to solve deficiencies in standard Rest specifications (or lack thereof). For example, JSON:API has a specified format: there is a schema describing the data, a place for metadata, links to related resources, described error messages, and so on. It has support for determining what data the server returns which reduces the amount of data that needs to be sent. Moreover, it is possible to retrieve multiple entities at once, significantly improving app performance.
There is also GraphQL, a query language developed by Facebook that solves the above shortcomings by placing more responsibility on the side where the data is retrieved. Instead of fixed endpoints like Rest and JSON:API have, GraphQL basically has one endpoint that the frontend can make requests to. The requester can determine which data is retrieved using a query language. This can include filtering by fields and retrieving relationships between entities. The way these requests are made (the schema) is clearly described and documented but can become so complex that the use of wrapper libraries is actually a must.
Dries Buytaert has written an extensive article comparing these techniques.
Our choice for the time being has fallen on Rest. This is mainly because it works out-of-the-box with Drupal, is considerably less complex to start with, supports caching by default and is easy to implement in the frontend. Separating data and presentation through our setup with Redux and React also makes writing easier. In addition, we continue to find alternative solutions, particularly to further increase speed.
Decoupled Router
One of our wishes was to provide users with more of an app experience where a click to a follow-up page does not refresh a page. Among other things, React is suitable for Single Page Applications (SPA). Originally intended for web application applications, it also provides a pleasant user experience for purely informational websites.
This ensures that determining which page to show to the user (called routing) now becomes a front-end task instead of a backend task. However, because content managers can create new pages in the CMS, the web app does not know about the existence of these pages. Creating a new deploy every time a content manager creates a new page is obviously not a solution.
Fortunately, there is a Drupal module called Decoupled Router. This module provides an endpoint where a URL path can go in and a page comes out. As soon as the user requests a page, React can thus make a request to this endpoint. From the endpoint's response, the app can determine which page it is and how to display it.
Pros and cons
As mentioned, our solution is not for every project. To help you determine if our solution is right for your project, we list the pros and cons here.
Advantages
- More options, more freedom and more speed in development
As mentioned, Drupal is a hugely powerful CMS and virtually irreplaceable in our solution. In terms of frontend, great strides have also been made in Drupal 8. Recent developments in frontend development now offer much more possibilities and freedom. Combined with a faster way of developing, we no longer need to solve everything with Drupal. Our solution therefore allows you to keep using strong components but replace less strong ones. More flexibility by separating systems
Separating systems (decomposition) is a well-known strategy in software development. Instead of one big monolithic whole, it becomes a system of loosely functioning parts that communicate with each other. This is exactly the design of a headless system and gives flexibility: the presentation is separate from the data and both systems can function independently of each other, even be replaced as needed.Better use of specific knowledge of developers
Despite the fact that our way of working encourages people to be broadly applicable (T-shaped), there is a logical separation between developers who focus primarily on data, structure and logic (backend developers) and developers who focus primarily on presentation and user experience (front-end developers). With the separation of these two layers, developers can focus more on the area where they feel at home and do not have to deal with developments on the other system.- Better reuse of components
In Drupal, we use Features to share components between different sites. This works well for purely functional components but not so much for the presentation layer because in Drupal this is not strictly separated and thus interwoven into the Features. This has improved significantly with the advent of Twig, particularly with the ability to 'exteriorize' templates. However, if you use CSS, it remains a matter of stacking by means of overwriting, excluding, etcetera. This is generally doable but takes more effort to do cleanly.
Because of the strict separation between functionality and presentation, we can fairly easily package functionality as Features on the Drupal side and package the presentation layer into components on the React side. The presentation layer can thus be completely replaced without touching the functionality layer and vice versa.
Disadvantages
A larger and more complex stack
Separating components within a system (decomposition) has the advantage that each component an sich becomes simpler and more manageable. An immediate disadvantage, however, is that if separating means using different techniques for each component, the overall stack becomes larger and thus more complex. This is mainly a theoretical problem as far as we are concerned; in practice, it remains that this in fact gives only advantages.No server-side rendering by default
Server-side rendering has the advantage that a user gets back a fully built page when a page is visited. With techniques like React, that responsibility lies with the browser by default: the server returns the data needed to build a page, the browser then builds this page. An advantage is that the server has to do less work for this; that responsibility now lies with the browser. Although after loading the site in fact no longer needs to be fully loaded (because of the Single Page Application principle) it remains a direct disadvantage that the site may feel slower initially. React does have the possibility for server-side rendering but this makes the system considerably more complex because there is yet another process that has to run on the server.Search Engine Optimization
SEO is the comprehensive term for optimizing the degree of findability on search engines. This includes elements such as speed, structure and layout, readability and accessibility. The way this is determined focuses on the way websites are built on the server side. This ensures that sites built on the browser side cannot be indexed as well, and thus will give a poorer SEO score.
Many developments have been made in recent years, particularly by Google, to index such websites as well. So this concern has become less of a concern. However, for sites like Bing, Facebook, LinkedIn and Twitter, there is little or no support for this. A simple example is sharing a link to a Web site on Facebook. There is currently no preview of sites that are not server-side rendered.
Steps to an even better solution
The system we set up is currently running successfully on two sites: Unc Inc's own current website and Espero's new website (under development). But in the meantime, we are also working on the next steps to further increase its benefits and applicability.
Optimization speed and SEO
We have already taken the necessary steps to increase findability by, for example, partly rendering the pages server-side. However, this still relies heavily on Drupal so we still use two systems for rendering, something we would like to see changed in the future. And in terms of speed, there are still many steps to take as well. Google's PageSpeed Insights often still gives a lower score because of the longer "time to first interaction," the result of the longer loading of the page in the browser. Server-side rendering can improve a lot in this regard.Increase reusability
Since we have to develop a lot of functionality partly from scratch, reusability is paramount: everything we produce within this system must be reusable in future projects.Extension component library
Part of the reusability lies in the creation of a component library: a kind of catalog of reusable components, similar to a style guide, for example. We have already added components for navigation, pages, categories, views, paragraphs and forms. In the near future we will expand the library with components such as search, facets, comments and in-page editing.
A headless CMS, something for you?
Every situation is different, every website has its own requirements. Do you need a sounding board or are you looking for advice on the best possible setup for you? Then contact us and we'll be happy to help you get started.