
Migrating a React Blog From Mock Data to a File-Based System
React
MDX
Building a modern blog is a journey of solving a series of interesting problems. This post is a straightforward summary of the challenges faced and solutions implemented while migrating a React blog from a single mock-data file to a scalable, file-based architecture using Vite and MDX.
Problem 1: The Monolithic Mock File
- Problem: Initially, all blog posts were hardcoded in a single JavaScript array (
mockBlogPosts). This was difficult to manage, not scalable, and mixed content directly with application code. - Solution: Adopt a "one post, one file" architecture. Each post was migrated to its own
.mdxfile within asrc/data/blog/directory. Metadata like the title and date was stored as frontmatter.
Problem 2: Reading Local Files in Vite
- Problem: Unlike a backend server, a client-side application built with Vite cannot use Node.js's
fsmodule to read files from the file system. A different approach is needed. - Solution: Leverage Vite's native features. By using
import.meta.globin ourutils/blog.tsfile, we could instruct Vite to find and import all.mdxfiles at build time, making their content and frontmatter available to the application.
Problem 3: The Stubborn MDX Parsing Error
- Problem: The MDX parser (
@mdx-js/rollup) would fail with anacornsyntax error when it encountered TypeScript code containing generics (e.g.,React.FC<Props>) inside a code block. It misinterpreted the TypeScript as invalid JSX. - Solution: Instead of complex configuration changes, the most reliable fix was to slightly alter the code inside the
.mdxfile to remove the ambiguity. ChangingReact.FC<Props>to a function with an explicit return type ((props: Props): JSX.Element) resolved the parsing issue entirely.
Problem 4: Code Blocks Without Syntax Highlighting
- Problem: Once the parsing errors were fixed, the content rendered correctly, but all code blocks were monochrome and difficult to read.
- Solution: We implemented
react-syntax-highlighter. The key was to create a customMDXComponents.tsxfile that maps thecodetag to a component that uses<SyntaxHighlighter>. This map was then passed as a prop to our rendered MDX content (<Content components={...} />) on the blog post detail page.
Problem 5: Handling Asynchronous Data
- Problem: The new
getBlogPosts()function becameasyncbecause it relied on Vite's dynamic imports. Calling it synchronously in the UI components (Index.tsx,Blog.tsx) resulted in the error...slice is not a function, because the code was trying to slice aPromiseinstead of an array. - Solution: Refactor the UI components to use the
useEffectanduseStatehooks. The components now initialize with an empty state and fetch the blog posts asynchronously insideuseEffect, populating the state once the data arrives.
Final Result
By systematically addressing these five challenges, the blog's architecture was successfully transformed into a modern, clean, and developer-friendly system where content and code are completely separate.