Introduction
This post documents my learnings and the steps I took to implement syntax highlighting in a Next.js Markdown blog.
I was using Gatsby before; one benefit of using Gatsby was the rich ecosystem of plugins. To add syntax highlighting in Gatsby, you add plugin. For Next.js, you need to use several libraries, write more custom code, and understand the tradeoffs in the different approaches.
This made creating a blog in Next.js challenging, but the benefit was more flexibility.
Prerequisites
I highly recommend going through the Next.js tutorial to get a high overview of how Next.js works. Once you go through the tutorial, you will feel more comfortable taking the task of adding syntax highlighting.
Setup
On Github, Next.js has several example implementations. Make sure to download the blog-starter example.
Markdown To Html
Let's move to the markdownToHtml.js
file. Here, transformation from Markdown to HTML is handle by remark-html
and remark
.
Coming from a Gatsby ecosystem, the remark name is a bit different from what remark in the unified ecosystem implies. As I learned from swyx's issue, there is no Prism plugin for remark
, so we have to use @mapbox/rehype-prism
.
1import remark from 'remark'2import html from 'remark-html'34export default async function markdownToHtml(markdown) {5 const result = await remark().use(html).process(markdown)6 return result.toString()7}
Implementation
Let's remove remark-html
and remark
from the markdownToHtml.js
file and install the following dependencies:
npm i unifiednpm i remark-parsenpm i remark-rehypenpm i rehype-stringifynpm i @mapbox/rehype-prism
Once we have installed all the dependencies, let's add them to the markdownToHtml.js
document. It should look something like this:
import unified from 'unified'import remarkParse from 'remark-parse'import remarkRehype from 'remark-rehype'import rehypeStringify from 'rehype-stringify'import mdxPrism from 'mdx-prism'export default async function markdownToHtml(markdown) { const result = await unified() .use(remarkParse) .use(remarkRehype) .use(mdxPrism) .use(rehypeStringify) .process(markdown) return result.toString()}
Recap
Let's walk through the code.
unified
is an interface for manipulating content. It does this by taking Markdown, HTML, or plain text, turning it into structured data, and making it available to other plugins.unified
also lets you write one line of code to chain a feature into the process, exactly what we are doing in themarkdownToHtml.js
document.remark-parse
processes the Markdown without compiling it to HTML.remark-rehype
is then used to transform the processed Markdown to HTML.rehype-stringify
is used to serialize the HTML.@mapbox/rehype-prism
- is a rehype plugin to highlight code blocks in HTML with Prism. Although we are not parsing MDX, we can still parse our Markdown with thisrehype
plugin.
And now, if you start Next.js in development and visit one of the pages that have markdown, you will not see any changes. This is because you still needed to add the Prism styles to get the syntax highlighting.
Add Prism Theme
There are several ways to add a Prism theme. I've found the more straightforward implementation is adding it via a CDN link in your meta.js document. I'm adding my favorite theme, night-owl.
<link href="https://unpkg.com/prism-theme-night-owl@1.4.0/build/style.css" rel="stylesheet"/>
Once you import Prism styles we're done! You now have syntax highlighting in your Next.js markdown blog! 🎉
Conclusion
Although you don't have plugins in Next.js, unlike Gatsby, you have several approaches to adding syntax highlighting through a wide array of libraries. It took me several hours of research to implement this feature. I hope that this post saves you some time!
If you want to add line highlighting capabilities check out @mapbox/rehype-prism. Props to Juan Olvera for expanding this capability. I took his fork and created my own, where I started working on adding line numbers. It is still progress. Hopefully, I'll get it up and running.
Please let me know if anything was unclear, or if there's anything else you'd like to see in this or a subsequent article.