Using Gatsby for a Wagtail build - a case study
Recreating the Torchbox site with headless Wagtail and Gatsby.
I was recently lucky enough to be involved in redeveloping the Torchbox website in a rather exciting new way. Our aim was to take the existing Wagtail build and re-create it as a headless site, which would provide the data for a super-fast front-end build using Gatsby. In this post I'll take you through some of the reasons for choosing this way of working, the technical details of how it works, and some of the challenges we faced along the way.
What does headless mean?
No websites were decapitated in the making of this movie… Headless simply means that rather than the front-end being part and parcel of the Wagtail build, with Django templates rendering the pages, we send all content via an API to a separate front-end build.
Why would we want to do that?
The big benefit is that we can use Gatsby to serve up our site. Gatsby uses a combination of React and static site generation to create a super-fast site. It reads in data from the Wagtail API via GraphQL queries, and then generates a set of page templates and components using React. Only the essential HTML, CSS and JavaScript is loaded first, and then the data for other pages and resources is ‘pre-fetched’, meaning that subsequent page loads are lightning fast.
Another benefit is the separation of concerns between front-end and back-end code. A Gatsby site can pull in data from anywhere, meaning that the front-end code is not limited or constrained by the technology that the back-end code is built on. However, as I will discuss below, that also leads to a more complex workflow.
Although a relatively new technology, Gatsby has excellent documentation, so this was a big help to us when developing the site.
GraphQL
As outlined above, the data from the Wagtail API is pulled in via GraphQL queries on the Gatsby build. GraphQL is a query language that aims to make querying data quick and simple for developers. A big plus with using GraphQL for developers is the Integrated Development Environment (IDE) that allows you to build up queries on the fly, with autocomplete to see what data is available. For example, I might want to find out what data is available on a person page template. I can start constructing my query, by adding the following code:
query { }
Within the curly brackets I can then type ‘p’, and I can automatically see a list of content types, starting with those beginning with ‘p’. I select ‘personPages’, and add another set of angle brackets. At this stage I may not know what fields are available on this content type at all - I can simply type ‘q’ (short for query), and it will show me a list of all the fields available.
This process of building up queries makes it quick and easy to pull in the data that the front-end build needs to display.
GraphQL also allows the use of ‘fragments’: re-usable query subsets for situations where we are frequently querying the same information. This was very useful in the Torchbox build for our image queries; we re-use the same image formats in multiple places, so it makes sense to re-use the queries that build them. The following piece of code pulls out a full-size image (the original upload size) from Wagtail:
fragment fullImage on ImageObjectType { src: rendition(format: "full") { url width height } alt }
It can then be used from other queries, for example in this simplified version of the query for the person page:
personPages(slug: $slug) { pageTitle searchDescription image { ...fullImage } }
You can try out the GraphQL IDE for yourself at https://trygql.com/. And take a look at Brent's post about getting started with Wagtail and GraphQL.
Components
Because the site uses React, the site is built of a set of re-usable components. We create a ‘page’ component for each type of page in the site (for example person pages, blog posts, service pages etc). The page components will then call child components to display the elements on the page, for example Title, Streamfield content or Contact information. In some cases, the components will be several levels deep. Each component stores the JavaScript to render it alongside the CSS used to style it.
What else was new to this build
Another new element for me in this build was using CSS modules to author CSS. Traditionally, CSS is tied to a class or to an HTML element (or even an ID, although this is usually avoided), and can then be used anywhere in the site which uses that class or element. This can lead to problems if a classname is accidentally re-used or if a class is used widely throughout the site and a change is needed. Naming methodologies like BEM mitigate this risk, but CSS modules takes this to a new level. CSS is forcibly scoped to a particular component. It is compiled as JavaScript, which appends random strings to classnames to ensure they are scoped to just one component. If you want to find out more there’s a good CSS Tricks article you can read.
While this took a little getting used to, it did force me to consider my CSS naming very carefully, and to avoid situations where the CSS styling was dependent on a parent component.
The challenges
Inevitably, trying out a new approach for building a site brings some challenges and some problems.
Workflow
Separating back-end and front-end development frees you to use the best technology choices for both aspects of the build, but it also leads to a more complicated workflow. Say we decide to add a short biography for each person, summarising their interests outside work. We first need to add that to the Wagtail model and to the API, so that it is available on the front-end. We need to get that change code-reviewed, tested and deployed to the live site, and only then can we query it from the Gatsby build and add the information to our component on the front-end. If it turns out we need slightly different data that we originally thought, we’ll need to go back and repeat that process again. If we want back and front-end changes to go live at the same time, it means that as front-end developers we need to have working local builds for both the back-end and front-end, so that we can work off the branch where the new back-end code has been developed.
Data transfer between components
For each page type on the site we create GraphQL queries of the data that needs to be displayed, but that is not the end of the process. Because each page type is built up of re-usable React components, we need to pass the data down to those components via props (React’s way of passing information from parent to child components). As components can be several levels deep, this can mean that one piece of data may be passed as props through several components before it can be displayed. As front-end developers, we end up spending more time querying and passing data around than we would in a traditional server-rendered build where the data is immediately present in the template.
Ensuring we follow all the best practices we have set up by default for our traditional Wagtail builds.
We've been building Wagtail sites for many years now, and as a result we have a sophisticated starter kit for those kind of builds which ensure we remember everything from making sure we set a language attribute on the HTML, to making sure that the Twitter sharing tags are in the correct format, to making sure that the SEO description is set up correctly with suitable fallbacks if the relevant field is left blank in the CMS. With our Gatsby build we were starting from scratch with all of those elements, so it was a challenge to ensure we built our pages to the same high standards.
Sometimes it can be quite complex to make simple changes
For example, in order to add meta-data such as title and description to the site, it is necessary to add a special plugin called react-helmet, and then create an "seo" component which will set some defaults, and then pull in the relevant data from each page’s query. Compare this to simply adding the information in the `base.html` template in a traditional Wagtail build, and it can feel a little convoluted.
Conclusions
It has been a fascinating process to work on this build and learn a completely new approach to building the front-end of a Wagtail website. The benefits are certainly compelling, and although there have been some challenges along the way, I’m sure there will be solutions we can work on for future builds like this.
Do also have a look at this blog post from Will (and admire the new Torchbox.com site at the same time!)