If you’re writing a technical blog, syntax highlighting is a must.
So in this post, let’s set it up.
The package we’ll use is a rehype plugin called Rehype Pretty Code, which does its highlighting with Shiki.
Prism is the famous name in syntax highlighting, but this time I went with a Shiki-based package.
Shiki is more accurate than Prism
Looking at other people’s write-ups, Prism’s highlighting isn’t always accurate and can break down in places — see this post about switching to Shiki (in Japanese).
Shiki, on the other hand, uses the same syntax highlighting engine as VS Code, which is reassuring.
Incidentally, Astro also uses Shiki as its default syntax highlighter — see Markdown & MDX 🚀 Astro Documentation.
So I concluded Shiki was the way to go.
And while researching how to use Shiki, I came across a rehype plugin called Rehype Pretty Code (rehype-pretty-code).
I learned about this plugin from a post about rebuilding a blog with Next.js (in Japanese). Thanks to the author.
What is Rehype Pretty Code?
Rehype Pretty Code is a rehype plugin that gives your MD/MDX documents beautiful code blocks.
I won’t go deep into it here, but it can also highlight specific lines and display line numbers and file names. For example, it can render something like this:
const add = (a, b) => a + b;
add(2, 3); // 5
For line highlighting, line numbers, and file names, see Adding line numbers and highlighting lines with Rehype Pretty Code.
Preparing to use rehype plugins
At the time of writing, this blog was built following the official Next.js tutorial, using remark and remark-html to convert markdown to HTML.
remark-html is a shortcut for .use(remarkRehype).use(rehypeStringify), but to use rehype plugins you need remark-rehype and rehype-stringify separately.
So, remove remark-html:
pnpm rm remark-html
And install remark-rehype and rehype-stringify:
pnpm add remark-rehype rehype-stringify
Then, in lib/posts.js, import them and drop remark-html:
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import { remark } from 'remark';
import html from 'remark-html';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
Next, update getPostData, which uses them:
export const getPostData = async (id) => {
const fullPath = path.join(postsDirectory, `${id}.md`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
const matterResult = matter(fileContents);
const processedContent = await remark()
.use(html)
.use(remarkRehype)
.use(rehypeStringify)
.process(matterResult.content);
const contentHtml = processedContent.toString();
return {
id,
contentHtml,
...matterResult.data,
};
};
Rehype plugins go between the .use(remarkRehype) and .use(rehypeStringify) we just added, so that’s where rehype-pretty-code will live.
Setting up Rehype Pretty Code
Now that we’re ready for rehype plugins, let’s set up rehype-pretty-code.
First, following the official documentation, install the required packages:
pnpm add rehype-pretty-code shiki
Next, import rehype-pretty-code in lib/posts.js:
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import rehypePrettyCode from 'rehype-pretty-code';
import rehypeStringify from 'rehype-stringify';
import remarkRehype from 'remark-rehype';
Then update getPostData to use it by adding .use(rehypePrettyCode):
export const getPostData = async (id) => {
const fullPath = path.join(postsDirectory, `${id}.md`);
const fileContents = fs.readFileSync(fullPath, 'utf8');
const matterResult = matter(fileContents);
const processedContent = await remark()
.use(remarkRehype)
.use(rehypePrettyCode)
.use(rehypeStringify)
.process(matterResult.content);
const contentHtml = processedContent.toString();
return {
id,
contentHtml,
...matterResult.data,
};
};
Syntax highlighting now works.
Changing the theme
Personally I like One Dark Pro as a highlighting theme, so let’s switch to it.
Changing the theme is easy — just pass it as an option when using the plugin. For themes bundled with Shiki, a string is all you need.
Add theme: 'one-dark-pro' as in the example below.
The keepBackground: true added alongside it tells the plugin to use the background color defined by the theme. If you want to use your own background color, set it to false.
const processedContent = await remark()
.use(remarkRehype)
.use(rehypePrettyCode, {
theme: 'one-dark-pro',
keepBackground: true,
})
.use(rehypeStringify)
.process(matterResult.content);
You can browse the themes bundled with Shiki at Themes | Shiki.
Even themes not bundled with Shiki can be loaded from JSON. See the documentation for details.
Wrapping up
With that, this blog finally has syntax highlighting.
Rehype Pretty Code has more handy features, like highlighting specific lines and adding line numbers.
I was planning to cover those in a later post — and here it is 👉🏼 Adding line numbers and highlighting lines with Rehype Pretty Code