Migrating from gatsby-remark-prismjs to prism-react-renderer
I am gonna share a bit about how I have integrated with prism-react-renderer
and kept the
styles I was using back with gatsby-remark-prismjs
. As I migrate my blog over, I want to record
a bit better about the tools I have been using. One of the most important things for me
as I switch to MDX has been maintaining the readability of my code blocks. I won’t be talking
about how to install MDX, but the maintainers have a
great set of docs about it for Gatsby (which is what I use)!
Adding a CodeBlock
component to MDX
In a layout file (typically the topmost one), import MDXProvider
. This is where one can add in
custom components that will override how their markdown renders it. These each match to some
shortcode. In my case, I needed to declare the component
for code
. I went to my src/pages/layout.js
and added:
// src/pages/layout.js
import React, {Fragment} from 'react'
import {MDXProvider} from '@mdx-js/react'
import CodeBlock from 'src/components/CodeBlock'
// ... some more imports
const components = {
pre: props => <div {...props}>,
code: CodeBlock
}
const Layout = ({ children }) => (
<MDXProvider
components={components}
>
{/* */}
</MDXProvider>
)
The pre
will always wrap around our code
by default so we need to make sure
to pass through any props we receive down to the code block. In addition, we
can pass in any additional styles on the pre
wrapper. I do this so I can
support smaller devices with my line highlighting.
Writing our CodeBlock
component
We told our layout.js
that we should be using our CodeBlock
component so let’s go ahead and create that.
We’ll use prism-react-renderer
’s Highlight
component to handle how to present everything on the screen.
This was an almost exact copy from MDX’s Syntax Highlight documentation
but some important things worth noting are:
// src/components/CodeBlock.jsx
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
export default ({ children, className }) => {
// Pull the className
const language = className.replace(/language-/, '') || ""
return (
<Highlight {...defaultProps}
code={children}
language={language}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<pre className={className} style={{ ...style }}>
{tokens.map((line, index) => {
const lineProps = getLineProps({ line, key: index })
return (
<div key={index} {...lineProps}>
{line.map((token, key) => (
<span key={key}{...getTokenProps({ token, key })} />
))}
</div>
)
}
)}
</pre>
)}
</Highlight>
)
}
- We need to pull the language off of our codeblock and we will get that from the
className
prop. We will make sure to use a big regex magic to get the language that we want. And pass that as a value to thelanguage
prop on<Highlight>
. - We will pass in the
children
as a value to thecode
prop on<Highlight>
. Then we’ll have all the syntax highlighting working by default!
Removing gatsby-remark-prismjs
And now… we can just remove the plugin entirely from our gatsby-config.json
and everything should still
work!
plugins: [
'gatsby-plugin-theme-ui',
'gatsby-plugin-mdx',
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
- {
- resolve: `gatsby-remark-prismjs`,
- options: {
- classPrefix: 'language-',
- inlineCodeMarker: `>`,
- showLineNumbersGlobal: false,
- noInlineHighlight: false,
- },
- },
// ....
]
}
}
]
Updating Theme
At this point there is nothing else left but customizations! If you’re like me, you want to make your site a bit personal so I will show you:
- Using other preset themes
- Reusing themes you had with
gatsby-remark-prismjs
Preset Themes
prism-react-renderer
has a bunch of preset themes. You can find the list
here. By default, it uses the duotoneDark
theme.
Import the specific theme you’d like and pass it as the value for the theme
prop on Highlight
:
// src/components/CodeBlock.jsx
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
import vsDark from 'prism-react-renderer/themes/vsDark';
export default ({ children, className }) => {
// Pull the className
const language = className.replace(/language-/, '') || ""
return (
<Highlight {...defaultProps}
code={children}
language={language}
theme={vsDark}
>
{/* ... */}
</Highlight>
)
}
Reusing the gatsby-remark-prismjs theme
You might have had a custom theme installed through your gatsby-browser
. I have been using
prism-atom-dark
theme for a long time and it has been great! To keep using it, I just needed
to tell the theme
is undefined
. This is an escape hatch that let’s prism-react-renderer
know
we will handle the themes with global CSS declared elsewhere.
Make sure in you have your css file imported:
// gatsby-browser.js
// This is the source path to my CSS theme
require('./src/assets/css/prism-atom-dark.css')
Then in our CodeBlock
component:
// src/components/CodeBlock.jsx
import React from 'react'
import Highlight, { defaultProps } from 'prism-react-renderer'
export default ({ children, className }) => {
// Pull the className
const language = className.replace(/language-/, '') || ""
return (
<Highlight {...defaultProps}
code={children}
language={language}
theme={undefined}
>
{/* ... */}
</Highlight>
)
}
Conclusion
And that’s a wrap! This was an excellent fun project for me over the weekend. There are a few things I will
expand on, like how do I keep my line highlighting now that I am using prism-react-renderer
! Let me know if this
helped you out!
P.S. Thank you to Ryan Warner for inspiring me to take on this project!