Published: December 10, 2020
Add highlight.js Syntax Highlighting to a Gatsby-rendered Drupal Website
When every tutorial for syntax highlighting in Gatsby talks about highlight.js markdown but you have a Drupal website, you need to write your own for posterity. Here's mine.
This website uses the very helpful CKEditor CodeSnippet module to provide syntax highlighting. That in turn uses highlight.js. However, while investigating using Gatsby for the frontend of this website, I came across the headache of adding code highlighting to the site, when my code is just a string in the body field. Here's my solution ... if you have a better one, let me know in the comments.
Create custom utility function for highlight.js
- Add highlight.js to your repo
npm install highlight.js
- Create a file at
/src/utils/highlightCode.js
. - Import the library and the CSS style you want to use
- Set the languages you want to load (we don't need to load all of them for performance reasons)
- Create a function in this file that finds every instance of your code element and loop through it to let highlight.js work on each instance. That file will look something like this:
import hljs from 'highlight.js'
import 'highlight.js/styles/monokai-sublime.css'
hljs.configure({
languages: [
'php',
'javascript',
'json',
'bash',
'scss',
'css',
'yml',
'twig',
'html',
],
})
export default function highlightCode() {
const codeBlocks = document.querySelectorAll('pre > code')
codeBlocks.forEach(codeBlock => {
if (typeof codeBlock === 'object') {
hljs.highlightBlock(codeBlock)
}
})
}
Use the useEffect()
hook to apply this to our template
In my case, I wanted to apply this to the article template, which means attaching it to the
<div dangerouslySetInnerHTML={{ __html: nodeArticle.body.value }} />
but by the time Gatsby has grabbed and rendered that, it's too late. Instead, we add our useEffect()
before we render our article - this is basically the hook_preprocess_node()
of React! That's looks like this:
// import React, etc, etc
import highlightCode from '../../utils/highlightCode'
export default function SingleArticlePageTemplate({ data }) {
useEffect(() => {
highlightCode()
})
return (
<>
<Layout>
// Stuff before body field (title, image, etc)
<div dangerouslySetInnerHTML={{ __html: articleBody }} />
// Stuff after body field (tags, etc)
</Layout>
</>
)
}
It's pretty simple, hopefully it will help you/save you some time Googling.