When building a developer-focused blog, having a robust markdown processor isn't just a nice to have, it's essential. Markdown makes writing blog posts easy, and processing it effectively means presenting code snippets beautifully, clearly, and functionally.
In this post, I'll explain step-by-step how I built a flexible and powerful markdown processing pipeline using unified, remark, rehype, and rehype-pretty-code to render visually appealing and interactive code blocks.
Why Markdown
Markdown is a lightweight markup language that's easy to read and write. Developers commonly use it because:
- It's simple, intuitive, and fast to write.
- It cleanly separates content from presentation.
- It integrates smoothly with static site generators and frameworks.
The Goal: Great Markdown Experience
I wanted my markdown processor to:
- Efficiently parse markdown to HTML.
- Display syntax-highlighted code snippets.
- Include an interactive copy button for code blocks.
Let's dive into how I achieved this.
Step-by-Step Implementation
1. Reading the Markdown Files
The first step is straightforward: read the markdown file content from a directory.
const filePath = path.join(articlesDirectory, `${slug}.md`);
const fileContent = fs.readFileSync(filePath, "utf-8");
articlesDirectory
is the folder containing all your markdown files.slug
is the unique identifier for each markdown file.
2. Parsing Frontmatter
Frontmatter provides metadata about the markdown post (e.g., title, description, tags).
I use the popular library gray-matter
:
const { content, data } = matter(fileContent);
content
contains the markdown body.data
contains metadata like title, date, etc.
3. Markdown Processing Pipeline
Now, let's convert markdown content into HTML. We'll use a powerful combination of tools:
- unified: A toolchain for content transformation.
- remark: Parses markdown into a syntax tree (MDAST).
- rehype: Converts markdown syntax tree (MDAST) into an HTML syntax tree (HAST).
- rehype-pretty-code: Highlights code snippets beautifully.
Here's the full implementation:
const htmlContent = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypePrettyCode, {
theme: "github-dark",
transformers: [
transformerCopyButton({
visibility: "always",
feedbackDuration: 3_000,
}),
],
})
.use(rehypeStringify)
.process(content);
4. Understanding the Processors
Let's break down each step clearly:
remarkParse
: Converts markdown text into an abstract syntax tree (AST).remarkRehype
: Transforms the markdown AST into an HTML-compatible syntax tree.rehypePrettyCode
: Provides syntax highlighting for code blocks. I'm using the github-dark theme for clear visibility.transformerCopyButton
: Adds a copy button to code blocks, improving user experience.rehypeStringify
: Generates an HTML string from the processed syntax tree.
5. The Result
This implementation allows markdown files to render into clean, syntax-highlighted HTML effortlessly:
- ✅ Beautiful code syntax highlighting.
- ✅ Easy-to-use copy-to-clipboard functionality.
- ✅ Highly customizable themes and transformations.
Enhancements and Customizations
This solution is highly flexible. You can easily:
- Switch between multiple themes (dracula, nord, github-dark, etc.).
- Add other remark/rehype plugins to enrich your markdown experience (e.g., adding image optimizations, emoji support, or automatic link transformations).
Conclusion
Building a robust markdown processor significantly improves the readability and overall experience of your blog, especially for technical audiences. Using unified, remark, rehype, and rehype-pretty-code, you gain complete control over how your markdown content is presented, enhancing readability and interaction.