Arisa Fukuzaki
Posted on May 22, 2021
Hi there!
I'm Arisa, a DevRel from this June living in Germany🇩🇪 (A big announcement is coming this June😏)
I have a free online programming learning community called Lilac, with free hands-on Frontend e-books👩💻
Who is this article for?
- Anyone who wants to try out integrating syntax highlight in the Storyblok blog project
- Anyone who wants to build a tech blog with Storyblok & Gatsby.js
- Anyone who wants to know the syntax highlight integration in a Headless CMS with Gatsby.js
To help you understand the prep before integrating syntax highlight in rich text from Storyblok, here are some resources to read📖
Storyblok: The Complete Guide to Build a Full-Blown Multilanguage Website with Gatsby.js
I highly recommend you to take a look at the blog post I wrote below.
This blog post requires you to have a basic understanding of the fetching rich text from Storyblok.
The blog post below helps you with hands-on source code :)
[Storyblok, Gatsby] Programmatically create blog post pages from data
Step 1: Fetch node resolvers, NODE_CODEBLOCK
with storyblok-rich-text-react-renderer
At this point, I expect you that you completed to generate a blog entry page dynamically with using gatsby-node.js
file.
If you feel I started to talk about unicorns, go grab my blog post I recommended you above🦄
First things first, install storyblok-rich-text-react-renderer
if you didn't have yet from the blog post I recommende you to take a look at first.
$ yarn add storyblok-rich-text-react-renderer
Import render
from storyblok-rich-text-react-renderer
.
If you followed the blog I asked you to take a look at first, it'll look something like this.
import { render } from 'storyblok-rich-text-react-renderer'
export default function BlogEntry({ pageContext, location }) {
let story = pageContext.story
story = useStoryblok(story, location)
return (
<Layout>
<p>{ story.content.intro }</p>
<div>
{/* 👇 render a rich text data */}
{ render(story.content.long_text) }
</div>
</Layout>
)
}
Technically, we already can see code_block
data content type in the browser without configuring the details of code_block
data content type.
It's because long_text
data content contains all rich text from Storyblok draft JSON.
code_block
is a data content type to stow code blocks from Storyblok's main dashboard content input.
But it's not with styles if you see the results in the browser.
Looks treated exactly the same style as paragraph data content type.
We want our code_block
data content type to be highlighted.
Step 2: Map node resolvers to custom React components
Don't be paranoid, I'll explain what's node resolvers are👍
The node resolvers are the optional second argument of the render
function from storyblok-rich-text-react-renderer
.
There're several values assigned from Storyblok.
render(document, {
markResolvers: { ... }, // inline elements
nodeResolvers: { ... }, // block elements
blokResolvers: { ... }, // embedded components
defaultBlokResolver: (name, props) => ( ... ),
defaultStringResolver: (str) => ( ... ),
});
Storyblok: Storyblok Rich Text Renderer for React, README, advanced usage
We'll use nodeResolvers
this time.
code_block
data content type is a block element.
It's all written in the documentation.
Storyblok: Storyblok Rich Text Renderer for React, README, node resolvers
We can use below for code_block
data content type.
NODE_CODEBLOCK — (children, { class }) => { ... }
Let's take a look at the example first.
import MyImage from 'components/MyImage';
import { render, NODE_IMAGE } from 'storyblok-rich-text-react-renderer';
render(document, {
nodeResolvers: {
[NODE_IMAGE]: (children, props) => <MyImage {...props} />
}
});
It's nothing different from the documentation.
Just the node resolver is an image in this case.
The only differences are below.
- We don't create a separated component for
code_block
to render - Use
NODE_CODEBLOCK
Based on that, we can write something like this.
import { render, NODE_CODEBLOCK } from 'storyblok-rich-text-react-renderer'
export default function BlogEntry({ pageContext, location }) {
let story = pageContext.story
story = useStoryblok(story, location)
return (
<Layout>
<p>{ story.content.intro }</p>
<div>
{/* 👇 render a rich text data & code_block */}
{
render(story.content.long_text, {
nodeResolvers: {
[NODE_CODEBLOCK]: (children, story) => {
return (
<pre>
<code { ...story }>{ children }</code>
</pre>
)
}
}
}
)
}
</div>
</Layout>
)
}
Let me tell you the results already before you get disappointed.
It won't make any change in the browser😅
It's because we already fetched code_block
when we rendered long_text
data content.
If so, why we did all those work?
Trust me.
Soon later, you'll know how this way is much easier than if you try out integrating Prism.js or highlighter.js by yourself.
It's less packages to install, no babel config is required and our code is very short.
But how we'll add the syntax highlight?
We'll combine with React Syntax Highlighter.
Step 3: Apply React Syntax Highlighter
To do that, let's install it first.
$ yarn add react-syntax-highlighter
Import SyntaxHighlighter
and a style theme.
import SyntaxHighlighter from "react-syntax-highlighter";
import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism';
You can choose your theme styles from their documentation.
The example from their documentation shows like this.
import SyntaxHighlighter from 'react-syntax-highlighter';
import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs';
const Component = () => {
const codeString = '(num) => num + 1';
return (
<SyntaxHighlighter language="javascript" style={docco}>
{codeString}
</SyntaxHighlighter>
);
};
It means, as long as we wrap our code elements with SyntaxHighlighter
component, it might work.
It'll be like this.
return (
<div>
{
render(story.content.long_text, {
nodeResolvers: {
[NODE_CODEBLOCK]: (children, story) => {
return (
<pre>
<code { ...story }>
<SyntaxHighlighter language={ story } style={ tomorrow }>
{ children }
</SyntaxHighlighter>
</code>
</pre>
)
}
}
}
)
}
</div>
)
I recommend you to debug children and story with console.log()
.
You'll see the values we want is returned.
Also, the syntax highlight theme is on🔥
In fact, NODE_CODEBLOCK
returns an opject property name, class
.
It means, we should be able to see that the class attribute value of "language-javascript"
must be added into our code snippet HTML elements.
You mihgt face some situations with the value of undefined if you forget to choose a language when you edit your content in a main dashboard.
As long as we choose the language from our main dashboar in Storyblok, this won't happen👍
Hope you found something relevant info for your project!
Posted on May 22, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.