In a previous post we learned how to render YouTube videos using the Rich Text Editor from Contentful, in this post we will learn how to render pretty code blocks using the Rich Text Editor from Contentful, I will assume that you already know:
How to connect your Gatsby page to Contentful using the gatsby-source-contentful
How to render the basic content from a rich text editor, here's a tutorial
With that said, let's start!
Adding code snippets to your post content
We will use the built-in code
option to insert our snippets to the posts, the problem I faced was that Contentful doesn't allow to specify the language of a snippet like the Github Flavored Markdown, so we cannot do things like this to manage highlighting:
``javascript
console.log("Hello World")
``
Instead, what I came up with was to use the first line of the snippet for metadata, like the language of the snippet, in that way the snippet above would be written like:
---
lang:javascript
console.log("Hello World")
Later in the code we will handle this metadata information, for now let's add it to the content of our post
Adding code highlighting to our blog
I was checking, and the most popular library by far seem to be PrismJS, it's easy to add to our Gatsby website, and it's easy to configure
Installation
To install it, you just need to run this
npm install prismjs babel-preset-gatsby babel-plugin-prismjs
Configuring PrismJS
We installed the babel-babel-preset-gatsby
package to be able to tell prismjs
which theme to use, and exactly which languages and plugins we want to support in our side and therefore not include unused features, for this we need to create a new file called:
.babelrc
{
"presets": [
"babel-preset-gatsby"
],
"plugins": [
[
"prismjs",
{
"languages": [
"javascript",
"css",
"markup"
],
"plugins": [
"show-language",
"line-numbers"
],
"theme": "tomorrow",
"css": true
}
]
]
}
-
You can see in the snippet above that the languages we will support in the blog are:
javascript, css, markup
- To see a list of all the supported languages, check here
-
The plugins we support are
show-language
andline-numbers
- Again, if you want to see all the supported plugins, check their doc
Finally, enabling PrismJS in our application
The last step is simply to call Prismjs
to start coloring all the <code>
tags that it finds, I did it by calling the function inside a useEffect
in the React Component that is rendering the blog post
useEffect(() => {
// call the highlightAll() function to style our code blocks
Prism.highlightAll();
}, []);
Rendering the right HTML tags
In the section of the code where we render the basic content of the Rich Text Editor, we should add a new option to the renderRichText
function, this new option is just a property inside the key renderMark
(A code block is a mark
in the Contentful language), so it would look like this
renderRichText(post.body, {
renderMark: {
[MARKS.CODE]: (text) => {
return (
<pre>
<code>{text}</code>
</pre>
);
},
},
});
In the code above, every time we find a code
block inside the Contentful rich text editor content, we will render the text inside a <pre><code>
tags, this is how Prismjs
is expecting our code to be
Extracting the language from the code snippet
Now we want to extract the language from the first line of the code snippet, we will look o line to avoid weird behaviors later, and we will use the following regular expression ^lang:(\w+)
to test the code snippet.
If the expression doesn't match, we'll render a basic
code
blockOtherwise, we will render the fancy
Prismjs
elements
Final code
renderRichText(post.body, {
renderMark: {
[MARKS.CODE]: (text) => {
const regex = /^lang:(\w+)/;
// If the code snippet doesn't have the expected metadata
if (!regex.test(text)) {
return <code>{text}</code>;
}
// Extract the language
const language = regex.exec(text)[1];
// Remove the first line to avoid including metadata in the rendered version
return (
<pre>
<code className={language-</span><span class="p">${</span><span class="nx">language</span><span class="p">}</span><span class="s2"> line-numbers
}>
{text.split("\n").slice(1).join("\n")}
</code>
</pre>
);
},
},
});
Top comments (0)