Creating a static MDXblog in Next.js 14 involves several steps, including setting up your Next.js environment, creating MDX files, and configuring your pages to render these files. Below is a comprehensive tutorial to guide you through this process:
1. Setting Up the Next.js Project
Initialize the Next.js Project:
Run npx create-next-app@latest my-mdx-blog to create a new Next.js project.
Navigate into your project directory using cd my-mdx-blog.
Install Dependencies:
Install necessary packages like fs, path, gray-matter, and next-mdx-remote using npm or yarn. For example:
bash
npm install gray-matter next-mdx-remote
2. Creating MDX Files
Create a Blog Directory:
Inside your project, create a directory named blogs where you'll store your MDX files.
Write MDX Files:
Each blog post will be an MDX file within the blogs directory. These files can contain JSX and markdown content.
Example MDX file (sample.mdx):
markdown
---
title: "Sample MDX File"
date: "2023-11-17"
description: "This is a sample MDX file."
---# This is a sample MDX file
This is a sample MDX file. It contains JSX and markdown content.
![Image](https://images.unsplash.com/photo-1506748686214-e9df14d4d9d0)
```javascript
console.log("Hello, world!");
```<YouTubevideoId="dQw4w9WgXcQ" />
3. Creating the Main Page
Import Necessary Modules:
Your Home component will import modules like fs, path, matter, and Next.js components.
Read and Process MDX Files:
Use fs to read the files from the blogs directory.
Process each file's contents with gray-matter to extract front matter (metadata) and content.
Render Blog List:
Use the extracted data to render a list of blog posts on the main page.
Each list item links to the individual blog post page.
javascript
import fs from"fs";
import path from"path";
import matter from"gray-matter";
importLinkfrom"next/link";
exportdefaultfunctionHome() {
const blogDirectory = path.join(process.cwd(), "posts");
const fileNames = fs.readdirSync(blogDirectory);
const blogs = fileNames.map((fileName) => {
const slug = fileName.replace(".mdx", "");
const fullPath = path.join(blogDirectory, fileName);
const fileContents = fs.readFileSync(fullPath, "utf8");
const { data: frontMatter } = matter(fileContents);
const date = newDate(frontMatter.date);
// Format the date to a readable string format// For example, "October 1, 2021"const formattedDate = date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
});
return {
slug,
formattedDate,
meta: frontMatter,
};
});
return (
<div><divclassName="flex flex-col gap-8"><h1className="font-bold text-4xl">Next.js MDXBlog</h1><div><p>A static blog built with Next.js and MDX</p></div><sectionclassName="flex flex-col gap-4"><h2className="font-bold text-2xl">Blog Posts</h2><ulclassName="flex flex-col gap-4">
{posts.map((blog) => (
<likey={blog.slug}className="border px-3 py-2 rounded-xl"><Linkhref={`/blog/${blog.slug}`}><h3className="font-bold text-xl">{blog.meta.title}</h3><div>{blog.formattedDate}</div><div>{blog.meta.description}</div></Link></li>
))}
</ul></section></div></div>
);
}
4. Creating Individual Blog Post Pages
Dynamic Routes:
Use Next.js dynamic routing to create a page for each blog post. Create a page file at app/blog/[slug]/page.tsx, and insert the code below.
javascript
import fs from"fs";
import path from"path";
import matter from"gray-matter";
import { MDXRemote } from"next-mdx-remote/rsc";
importYouTubefrom"@/components/mdx/youtube";
importCodefrom"@/components/mdx/code-component/code";
// Content for these pages will be fetched with getPost function.// This function is called at build time.// It returns the content of the post with the matching slug.// It also returns the slug itself, which Next.js will use to determine which page to render at build time.//For example, { props: { slug: "my-first-post", content: "..." } }asyncfunctiongetPost({ slug }: { slug: string }) {
const markdownFile = fs.readFileSync(
path.join("blogs", slug + ".mdx"),
"utf-8"
);
const { data: frontMatter, content } = matter(markdownFile);
return {
frontMatter,
slug,
content,
};
}
// generateStaticParams generates static paths for blog posts.// This function is called at build time.// It returns an array of possible values for slug.// For example, [{ params: { slug: "my-first-post" } }, { params: { slug: "my-second-post" } }]exportasyncfunctiongenerateStaticParams() {
const files = fs.readdirSync(path.join("blogs"));
const params = files.map((filename) => ({
slug: filename.replace(".mdx", ""),
}));
return params;
}
exportdefaultasyncfunctionPage({ params }: { params: { slug: string } }) {
// Params contains the post `slug`// Fetch the post content based on the slugconst props = awaitgetPost(params);
// Customize components for MDX rendering.// For example, the Code component will render code blocks with syntax highlighting.// The YouTube component will render YouTube videos.const components = {
pre: Code,
YouTube,
};
return (
<articleclassName="prose prose-sm md:prose-base lg:prose-lg mx-auto"><h1>{props.frontMatter.title}</h1><MDXRemotesource={props.content}components={components} /></article>
);
}
Get Static Props:
Implement getPost and generateStaticParams functions to fetch the content for each MDX file based on the slug.
Use fs to read the MDX file content and gray-matter to parse it.
Render MDX Content:
Use MDXRemote from next-mdx-remote to render the MDX content on the page.
Customize components like Code and YouTube for MDX rendering.
5. Styling and Custom Components
Styling:
Apply CSS or use a CSS framework like Tailwind CSS to style your blog pages.
MDX Components:
Create custom components like YouTube and Code to enhance your MDX content.
Select a hosting platform like Vercel or Netlify for deploying your Next.js blog.
Deploy:
Follow the deployment instructions provided by your chosen platform. Typically, this involves linking your GitHub repository and configuring build settings.
Continuous Deployment:
Set up continuous deployment so that every push to your repository automatically updates your live blog.
Conclusion
By following these steps, you will have a static MDXblog running on Next.js 14. The key is to effectively manage your MDX files and ensure they are rendered correctly on your Next.js pages. The combination of MDX for content and Next.js for rendering provides a powerful and flexible blogging platform.