Understanding the Limitations of Gatsby‑Source Drupal
Editor’s Note: Brian presented “Dealing with the Limitations of Gatsby Source Drupal” at Decoupled Drupal Days in New York on August 18, 2018, which elaborated on a number of concepts outlined in this post.
As we continue to build sites powered by Drupal 8, we’ve increasingly been challenging our assumptions of how we can best render content provided by Drupal on the front end. When projects have called for it, we’ve found success using JavaScript frameworks like React and Vue alongside data provided by APIs from Drupal in order to enhance front-end user experiences.
Personally, I’ve been focusing my efforts on using Drupal in combination with React, both due to a love for the un-opinionated and component-driven approach of the library, and also as a result of the momentum that React has within the Drupal community. All of this eventually led me to Gatsby, a self-described “blazingly fast” static site generator for React.
Gatsby and Static Site Generators
Similar to existing projects like Jekyll, Gatsby generates a completely static build of your site that can be hosted almost anywhere, including on a CDN or on services like Github Pages or Netlify. Except that unlike Jekyll, it allows you to use the modern stack of Node, React, and GraphQL as opposed to Ruby and the Liquid templating engine. It also really is mind-blowingly fast thanks to optimizations like code splitting, lazy loading, and prefetching resources. Finally, Gatsby has a robust ecosystem of plugins that allow you to easily pull in data from a wide variety of data sources, including Drupal. (For a more detailed introduction to Gatsby, consult either the Gatsby tutorial or this post on Decoupling Drupal with Gatsby.)
Gatsby and Drupal
I’ve been developing my personal site with Drupal and Gatsby since the beginning of the year, and while I’ve loved the process overall, I have run into some challenges related to using Drupal as a content source. I’ve had to adjust my expectations as I’ve found that some features that are straightforward in other Gatsby configurations have required additional effort to achieve while using Drupal. I’ve also noticed that others in the Drupal community who are using Gatsby seem to be using it with Markdown files as data, rather than using Drupal. Some of this is likely to balance out over time as people become more comfortable with Gatsby, but I think that the types of hurdles I’ve encountered on my personal site could also explain why I’m seeing more projects than I’d expect use Markdown rather than Drupal as a data source.
One issue that contributes to this is that many of the available Gatsby plugins are focused on dealing with data imported from the file system via the gatsby-source-filesystem plugin, or more specifically, data from Markdown files via the gatsby-transformer-remark plugin. This is great for many use cases, but when using gatsby-source-drupal as a data source I found that a number of the plugins I attempted to utilize didn’t apply to data from Drupal. Let’s look at a few specific examples in order to illustrate how this made working with data from Drupal more challenging than I initially expected.
Challenges: Configuring an Image Plugin
Consider the case of displaying content from Drupal in Gatsby that contains an image. One of the first results when searching the plugin list for “image” is gatsby-remark-images. This plugin generates multiple responsive versions of images in your source data and displays them using the “blur up” technique popularized by Medium. While this sounds desirable, the “remark” portion of the plugin name indicates that this plugin specifically operates on Markdown data, which prevents us from using it with gatsby-source-drupal.
Upon further inspection, the gatsby-image plugin can provide the functionality we need for an image field provided by Drupal. After installing and configuring the plugin, we can now begin to write GraphQL queries in our Gatsby templates that take advantage of these newly generated responsive images.
Assuming that we’ve added the default Drupal image field to a content type called “post,” a GraphQL query similar to the following would give us the URL to images included on all post nodes:
(Note: gatsby-source-drupal stores this image file reference under “relationships” rather than alongside fields like title and body.)
While that would give us the image from Drupal, what we really want is the local image files that have been processed using the gatsby-image plugin. For that result, we can adapt the query to the following:
It took a little experimentation and documentation review to come up with this query - the sizes() portion of the query is used for images that stretch across a fluid container, and …GatsbyImageSharpSizes is a query fragment which was a GraphQL concept that I wasn’t yet familiar with. But at the end of it all, we have a query that contains the image from Drupal processed by Gatsby, and we can use JSX similar to the following to render it in our Gatsby template:
<Img sizes={this.props.data.nodePost.relationships.image.localFile.childImageSharp.sizes} />
(Note: that is using Gatsby’s <Img /> component rather than the standard <img /> tag.)
It works, but it is still quite a bit of additional configuration and effort when compared to gatsby-remark-images. And the example above only covers a single image field, explicitly placed somewhere in your Gatsby template. gatsby-remark-images on the other hand will process an image regardless of where it is included in your Markdown.
Challenges: Image Placement
Could we achieve the same sort of flexible image placement with gatsby-source-drupal? On the Drupal side, the closest equivalent to that would be using the WYSIWG editor on a text field in Drupal. That will allow us to place an image anywhere in our text field, but we’ll run into challenges on the Gatsby side pretty quickly with that approach. By default, the image paths in the editor generated markup will be relative, which will prevent Gatsby from being able to locate the image. Even if you resolve that issue, you’ll still be getting an image tag with the source pointing to your Drupal server. This means that the images would only load if the image path on the Drupal server is publicly available and would not be included in the bundle created by Gatsby. The images also wouldn’t be able to take advantage of the responsive image processing we implemented using gatsby-image earlier.
For my personal site I’ve implemented a partial solution to workaround this issue. As outlined in our earlier example, I have a single image field on post nodes. In Gatsby I have a <PostImage /> styled component that renders the Gatsby <Img /> component with some additional styling. So in the body field in my Drupal content I’ll add:
<PostImage></PostImage>
where I’d like to place the image in the resulting Gatsby content. The end result looks something like this:
Typically in the Gatsby template we’d use React’s dangerouslySetInnerHTML prop (yes, that really is what it is called) to render the markup from our body field:
<div dangerouslySetInnerHTML={{__html: post.body.value}} />
To make use of the <PostImage> placeholder in my Drupal content, I instead use react-html-parser. React-html-parser will take the markup from my body field and parse it into equivalent React components. It also has a useful transform function that allows me to take the <PostImage> placeholder from Drupal and replace it with the actual React component when Gatsby processes the template. The resulting render method in the Gatsby template will look similar to:
If the <PostImage> placeholder is included in the Drupal body field markup it will now be replaced with the equivalent React component, complete with the image field from the post node processed by the Gatsby image plugins. And if at some point this data is rendered without Gatsby or even React, the <PostImage> placeholder should be ignored.
While it is helpful to be able to place a Gatsby processed image using this method anywhere within the flow of a body field, this doesn’t feel like a viable long-term solution. Instead, this seems like an opportunity for one or more Gatsby plugins to be created in support of gatsby-source-drupal that allows for more generic image handling. In the meantime, this image example might illustrate why fewer people than I’d expect are using Drupal with Gatsby. I’d imagine many start out with Markdown-based tutorials, and then find it difficult to justify the additional resistance to replace Markdown with Drupal as a data source. If the supporting Gatsby plugin ecosystem around Drupal as a data source continues to evolve, perhaps this resistance will dissipate as well.
My Future with Gatsby and Drupal
For me, I’m planning on sticking with Gatsby in combination with Drupal for the time being. I enjoy working with both Drupal and React, and the performance benefits offered by Gatsby’s static optimized builds really are astounding. I also like knowing that my data exists centrally in Drupal and doesn’t have to be migrated if I decide to render it using an alternative to Gatsby or even a future version of Drupal.
In the meantime, I look forward to talking more with those who are using Drupal as a data source for Gatsby projects, and discussing how we might be able to work together to make Drupal and Gatsby even easier to use together.