Gatsby-Contentful: Code Snippets

Rich Text Format Workarounds

Before we deep dive into the matter at hand, let’s familiarize ourselves briefly with the tools we are setting up our workaround for.

Gatsby: the static site generator

Gatsby is a free and open source framework based on React that helps developers build blazing fast websites and apps” - Gatsby front page. 

Now in my own words, Gatsby is a static site generator that bundles all the latest web development practices from webpack configuration, progressive web app philosophies, and development environment usability to optimizing your code for performance with techniques such as code splitting, code minification, and image processing. 

Gatsby uses a plugin interface with a rich and active community behind it that is constantly improving upon what they’ve masterfully created.

Contentful: the headless CMS

Contentful is a headless CMS with all the latest capabilities in managing your content from having an intuitive, customizable interface to optimizing for all different types of software and devices with their substantial SDK ecosystem and robust APIs. 

Why We Chose Rich Text Format

There were several options that we could have used for modeling our blog content. The options include either a long block of text, Markdown, or Rich Text Format. The advantages of each would be based on the size and formatting flexibility of each text format model. In the end, we chose Rich Text Format due to its support/ease of integration with Contentful and its formatting capabilities which include the ability to dynamically link and embed assets and entries within the general flow of text. 

Using Rich Text Format from the perspective of a non-technical blog writer, we are able to easily link assets such as static images within the flow of our blog article. In addition, Rich Text Format utilizes Contentful’s embedded entry feature. Embedded entries empower the engineering team to design, develop, and implement features such as image carousels, embedded social media posts, quote blocks, and, in our case here, code snippets. The last, but not least, slightly obvious benefit is the editing flexibility that Rich Text Format provides with the functionality of easily selecting heading types 1 - 6, to bold, italicize, underline, and strikethrough text, listing out bullet points, and many more.

Get on with it already. How can I get my code snippets to show?

First things first, we’re going to need to create a new markdown Content Type that can be used to create code snippets. To do that, we can create a new Content Type under the “Content Model” tab in your Contentful dashboard. From here, we’ll add a new field into our newly created content type and select ‘Long Text”. Under the “Appearance” tab, select “Markdown”. For additional information on creating content types, see these Contentful docs for more.

test

Next, we’re going to need to create the actual markdown entry and embed it into our Contentful rich text editor.  

We’ll create a simple Markdown entry for now. To syntax highlight based on the language, the markdown block will be prepended with the language of your choice. For example, if we were to syntax highlight with Javascript, we would use the following:

```js
console.log(“Tacos are delicious.”)
```

The same holds for html, css, etc:

```html
<!DOCTYPE html>
<html>

<head>
  <title>Fancy shmancy title</title>
</head>

<body>

  <h1>Welcome to the Cantina</h1>
  <h2>Taco Main Ingredients:</h2>

  <p>Tortilla</p>
  <p>Cilantro & Onions</p>
  <p>Al Pastor & Pineapple</p>
  <p>Guacamole salsa</p>

</body>
</html>
```

Once we’ve created our Markdown entry, it’s time for us to embed it into our Contentful rich text editor. I could describe how to do it in depth, but instead here’s a screenshot:

test

For the sake of brevity, I will not be going over how to access that data in the API response. Here is more information on embedding entries and accessing the embedded data in the Contentlful API response.

Next, we’re going to create our React component that will render the markdown into HTML with markdown-it and proceed to syntax highlight our markdown with PrismJS since we now have our markdown response from the Contentful API. Here’s what that looks like:

// src/components/MyAwesomeCodeSnippet.js
import React, { useEffect } from 'react';
import MarkdownIt from 'markdown-it';
import Prism from 'prismjs';

const md = new MarkdownIt({
  html: true,
  linkify: false,
});

const MyAwesomeCodeSnippet = ({ markdown }) => {
  useEffect(() => {
    Prism.highlightAll();
  });

  return (
    <div dangerouslySetInnerHTML={{ __html: md.render(markdown) }} />
  );
};

export default MyAwesomeCodeSnippet;

In this snippet of code, we’re creating a React component that receives markdown as a prop and returns a div that sets the innerHTML  to the rendered output of markdown-it’s instance. In addition, on each render cycle, we are syntax highlighting using the useEffect method and PrismJS. If we wanted to have more highlighting capabilities, we would have to add it within this useEffect hook. 

Last but not least, we have to configure PrismJS to include what languages we want to support. I opted for easy configuration using the babel plugin: babel-plugin-prismjs, however there are more verbose alternatives to load the language support. One thing with Gatsby though is that Gatsby starter projects contain a default .babelrc setup that works for most sites. In our case, we want to add a custom plugin to our default .babelrc. In order to do that, we’ll have to introduce our own .babelrc file and load gatsby’s babel presets along with our PrismJS babel plugin. Here’s what that looks like:

// .babelrc
{
  "presets": ["babel-preset-gatsby"],
  "plugins": [
    ["prismjs", {
      "languages": ["javascript", "css", "markup"],
      "plugins": ["show-language"],
      "theme": "okaidia",
      "css": true
    }]
  ]
}

Voila! Now your code snippets should be rendering and highlighted as such. Feel free to play around with the configuration to support desired languages and themes. 

TLDR: Create a markdown content type for code snippets. Embed that markdown entry into your Rich Text editor. Render the markdown using markdown-it npm package. Syntax highlight the markdown with PrismJS. Configure .babelrc file to include babel-preset-gatsby(if you haven’t done this already), babel-plugin-prismjs, and language, plugin, and theme support for PrismJS. 

Final Result:

// .babelrc
{
  "presets": ["babel-preset-gatsby"],
  "plugins": [
    ["prismjs", {
      "languages": ["javascript", "css", "markup"],
      "plugins": ["show-language"],
      "theme": "okaidia",
      "css": true
    }]
  ]
}
// src/components/MyAwesomeCodeSnippet.js
import React, { useEffect } from 'react';
import MarkdownIt from 'markdown-it';
import Prism from 'prismjs';

const md = new MarkdownIt({
  html: true,
  linkify: false,
});

const MyAwesomeCodeSnippet = ({ markdown }) => {
  useEffect(() => {
    Prism.highlightAll();
  });

  return (
    <div dangerouslySetInnerHTML={{ __html: md.render(markdown) }} />
  );
};

export default MyAwesomeCodeSnippet;

Conclusion

If you’ve made it this far, congratulations on your new code snippets for your Gatsby-Contentful app. There were other methods that I explored to render code snippets in a Gatsby-Contentful app. There were existing plugins such as gatsby-remark-vscode that I initially aimed to leverage, however this plugin is a dependency of gatsby-transformer-remark which directly parses local markdown files. The caveat with our Gatsby-Contentful app is that our data is stored and managed through the Contentful API, thus not allowing us to leverage these existing plugins. Ultimately, this led to the team creating a new unique solution that we are glad to share with you today.

Kevin Lam

Senior Software Engineer

Published: Jul 31, 2020

Updated: Oct 2, 20207 min read

More blogs

AWS Certified Team

Tech Holding Team is a AWS Certified & validates cloud expertise to help professionals highlight in-demand skills and organizations build effective, innovative teams for cloud initiatives using AWS.

By using this site, you agree to thePrivacy Policy.