Code editor showing MDX blog setup
back to blog

Hello World: Building a Minimal Blog with MDX

•2 min read
nextjs
mdx
react
blog

Welcome to my new blog! I've been meaning to create a space to share my thoughts on code, design, and the intersection of both. After some deliberation, I decided to build a minimal blog system right into my portfolio site.

Why MDX?

MDX combines the simplicity of Markdown with the power of React components. This means I can write content in a familiar format while still being able to embed interactive components when needed.

// Example: A simple React component in MDX
const WaveHello = () => {
  const [waves, setWaves] = useState(0);
  
  return (
    <button onClick={() => setWaves(waves + 1)}>
      šŸ‘‹ Wave hello! (Waved {waves} times)
    </button>
  );
};

The Setup

The blog system is surprisingly simple. Here's what powers it:

  1. Next.js - For routing and server-side rendering
  2. MDX - For content authoring
  3. rehype-pretty-code - For syntax highlighting
  4. gray-matter - For frontmatter parsing
  5. reading-time - For estimated reading times

Code Structure

The blog follows a simple file-based routing pattern:

src/
ā”œā”€ā”€ app/
│   └── blog/
│       ā”œā”€ā”€ page.tsx          # Blog listing
│       └── [slug]/
│           └── page.tsx      # Individual posts
ā”œā”€ā”€ content/
│   └── blog/
│       └── *.mdx            # Blog posts
└── lib/
    └── blog.ts              # Helper functions

What's Next?

This is just the beginning. I plan to write about:

  • Deep dives into React patterns
  • Performance optimization techniques
  • Design system architecture
  • Open source contributions
  • Side project post-mortems

The Beauty of Simplicity

Sometimes the best solution is the simplest one. This blog doesn't have comments, likes, or analytics. It's just words on a page, styled consistently with the rest of my site. And that's exactly what I wanted.

// The entire blog post fetching logic
export function getPostBySlug(slug: string): BlogPost | null {
  try {
    const fullPath = path.join(postsDirectory, `${slug}.mdx`)
    const fileContents = fs.readFileSync(fullPath, 'utf8')
    const { data, content } = matter(fileContents)
    const stats = readingTime(content)
 
    return {
      slug,
      title: data.title,
      date: data.date,
      excerpt: data.excerpt || '',
      tags: data.tags || [],
      readingTime: stats.text,
      content,
    }
  } catch {
    return null
  }
}

Stay tuned for more posts. I'm excited to share what I've been learning and building.