I recently moved this blog site from one running Drupal on a traditional LAMP stack, to a decoupled architecture with Drupal as the CMS backend and GatsbyJS providing static site publication in a serverless S3+Cloudflare frontend. I'll blog more about the pros and cons about this approach another time, but here I'm just writing up my approach to managing inline content (images, embedded presentations etc). This is quite low-level and technical.
One common problem is with inline images, that is images that are included in an html field, typically the body field of an article. These images will most often reference a URL that's handled by Drupal, whereas we want the the image to be handled by Gatsby so that we can make use of all of the functionality that comes with Gatsby's Image components such as late-loading, fluid styles, low-bandwidth previews etc.
One way of attacking this problem is by rewriting the body field within Gatsby, using Gatsby's inbuilt knowledge of React components to transform the html that comes out of Drupal.
Because Gatsby is built on React we can use the ReactHTMLParser component to pass in html and a callback function that is called for every node in the DOM, giving you the chance to transform it. Whenever we come across an <img> html tag we can replace it with an <Img> JSX component. But the <Img> component requires that you pass in the result of a graphql image query fragment. How do we know what to pass in?
It turns out that the answer is quite simple. Because files, including inline images, are entities in Drupal 8, Gatsby helpfully downloads them for us and we're able to query them. As a graphql query can have multiple 'roots' we can add the following query to our article's query template - this will return all the images with their associated Drupal uuid.
So, back in our ReactHTMLParser transform function we can simply get the uuid of the image, helpfully Drupal renders this in the data-entity-uuid attribute of the <img> tag, and we just iterate over all of our images until we find the one with the matching uuid and build our <Img> component out with that.
I've used a similar rewriting approach to embedding Github gists (seen in this article), and Speakerdeck presentations.
The problem here is that in regular html you'd embed these as script tags, but this doesn't quite work for React as the component lifecycle differs from that of the traditional DOM (html) lifecycle, and so scripts need to be triggered in the appropriate location (eg in the componentDidMount method of the component).
Using the transform approach any script tags are identified, and their type determined by matching a domain name in the src attribute (eg speakerdeck.com or gist.github), then replacing with an appropriate React component (either a SpeakerDeck or Gist).
There are other ways of getting Drupal and Gatsby working together - jmolivas has been looking at attacking these problems from the Drupal perspective too via the TUI editor and related gatsby plugin - it's well worth looking at that approach too.
Finally, here's the full jsx file that produces this type of article page that you're looking at right now.