Making MDX blog with Next.js - Part 1
Tags: nextjs, mdx, react
Published: 2020-10-12 00:00:00

---
title: "Making MDX blog with Next.js - Part 1"
date: "2020-10-12"
author: "Jashn Maloo"
excerpt: "Friendly tutorial of building MDX blog with Next.js while discussing some common issues."
series: "MDX blog with Next.js"
---

When I thought of making a blog with Next.js, the first technology that came in my mind was MDX, because why not? With Next.js, it's a superpower with features like -

- It is treated just like any other page
- One can insert react based components
- Can be imported as components to other files
- Super fast. There's no runtime.
- Being markdown based, it's simple and very flexible to use

**What about SEO ?**
Well, it's supported as well, add front-matter to it, parse it with gray matter or similar library and you're good to go.
(I use next-seo for SEO in Next.js apps, but it won't be covered in this series. You can watch [this amazing tutorial](https://www.youtube.com/watch?v=MA95q4Rj7g8) for next-seo.)

### Prerequisites

You should be well versed with basics of React. Knowledge of Next.js is a plus, but I will be discussing some foundations of [Next.js](https://nextjs.org/docs).

### So What's the process ?

I won't say it's super easy because I've spent days trying several ways to implement all the above discussed points. But once you know it, it's a cheesecake.
Of the problems generally faced with SEO, components, parsing, I'll be discussing them as we move forward. Rest assured, it'll be a complete tutorial for building your own MDX blog.

Considering that I'll go in as much details as I can, it will be 2 part series. First one will definitely be long, but easy. We'll do the basic setup, with theming, essential pages, functions will be created in this post,
while the next one will cover dynamic routing, handling components, front-matter in the post.

> Repo: [mdx-blog-nextjs](https://github.com/Jashnm/mdx-blog-nextjs)


## 1. Initializing project

Bootstrap Next.js project with `npx create-next-app` and provide name to your project. In this case I'll be calling my project `mdx-blog`.
After it is done, cd into the project directory(our root directory).

This is how a typical Next.js folder structure looks like -

![folder structure](https://dev-to-uploads.s3.amazonaws.com/i/xkkixeaxc0g9jl4nx81n.png)

pages folder is the one where all the routes respond to in Next.js, so that's really important.

## 2. Adding styles & dependencies

Let's install most of the dependencies now. I'll discuss about these as we start using these. You can use yarn or npm according to your choice, I'm going with npm.

```
npm i theme-ui @theme-ui/presets gray-matter @next/mdx
```

For this project, I'm using theme-ui as my UI library and for syntax highlighting in thee blog, you can go with whatever you like, Chakra UI or Material UI or any other.
So We're installing `theme-ui` and its other packages with `gray-matter` for extracting SEO details from MDX files, `next-seo` for inserting meta data in our pages and `@next/mdx` for MDX files support in Next.js

Now let's create `theme.js` file in root directory to provide a theme preset and basic styles, and add the following to it -

```js
// ./theme.js

import { roboto } from "@theme-ui/presets";

const theme = {
  ...roboto,

  containers: {
    page: {
      width: "98%",
      maxWidth: "840px",
      m: 0,
      mx: "auto",
      justifyContent: "center",
      height: "100%",
      py: "1rem",
      px: ["0.4rem", "2rem"],
    },

    postCard: {
      p: "2",
      borderRadius: "4px",
      border: "1px solid #eeeeee",
      width: "100%",
    },
  },

  text: {
    heading: {
      py: "0.4rem",
    },
  },
};

export default theme;
```

It contains basic styling enough to build a decent looking blog, rest we'll be doing inside our pages.

Okay, theme done. Now we goota make our `_app.js` file ready, it is a supereme file, just like index.js in CRA.
Many UI libraries require ThemeProvider at the global level, so let's add it in `_app.js`

```js
// ./_app.js

import "../styles/globals.css";
import { ThemeProvider } from "theme-ui";
import theme from "../theme";

function MyApp({ Component, pageProps }) {
  return (
    <ThemeProvider theme={theme}>
      <Component {...pageProps} />
    </ThemeProvider>
  );
}

export default MyApp;
```

Once done, make Next.js config file `next.config.js` in the root directory. In `next.config.js`, add the following code

```js
// ./next.config.js

const withMDX = require("@next/mdx")();

module.exports = withMDX({
  pageExtensions: ["js", "mdx"],
});
```

This config file is required to tell Next.js that we're using MDX files, so it should treat them as regular pages.
After this, you can literally start building pages in MDX in the pages folder and you'll be ablle to see them in your browser. But we're building a blog, so there are more things involved.

## 3. Writing first MDX file

So we're ready to make MDX pages, make a folder named `posts` in the root directory and make two MDX files, then add the following content

```js
// ./posts/getting-started-with-mdx.mdx
---
title: "Getting started with MDX"
date: "2020-10-10"
author: "MDX Team"
excerpt: "Making this in MDX for simplicity and flexibility"
---

## Why MDX ?

❤️ **Powerful**: MDX blends markdown and JSX syntax to fit perfectly in
React/JSX-based projects.

💻 **Everything is a component**: Use existing components inside your
MDX and import other MDX files as plain components.

🔧 **Customizable**: Decide which component is rendered for each markdown
element (`{ h1: MyHeading }`).

📚 **Markdown-based**: The simplicity and elegance of markdown remains,
you interleave JSX only when you want to.

🔥 **Blazingly blazing fast**: MDX has no runtime, all compilation occurs
during the build stage.

[MDX](https://mdxjs.com) is markdown for component era.

```

```js
// ./posts/some-random-points.mdx

---
title: "Writing random points"
date: "2020-10-09"
author: "Jashn Maloo"
excerpt: "World is random in what it does, so let's write something random"
---


## Some random points

- Isn't writing in markdown lovely?
- Aren't components so reusable?
- Why is Next.js so fantastic?
- Please give me 2021.

### Some random heading


```

Cool, but it's not yet ready to be shown on our site. Because it's outside our pages directory, first we'll make index page for all the posts we'll have and slug out of these file.

Make a `lib` folder in your root directory. A lib folder generally contains all that code that is needed to get information in pages to run properly.
In the `lib` folder, make a file named `posts.js` and add the following code to it

```js
// ./lib/posts.js

import fs from "fs";
import path from "path";
import matter from "gray-matter";

//Finding directory named "posts" from the current working directory of Node.
const postDirectory = path.join(process.cwd(), "posts");

export const getSortedPosts = () => {
  //Reads all the files in the post directory
  const fileNames = fs.readdirSync(postDirectory);

  const allPostsData = fileNames.map((filename) => {
    const slug = filename.replace(".mdx", "");

    const fullPath = path.join(postDirectory, filename);
    //Extracts contents of the MDX file
    const fileContents = fs.readFileSync(fullPath, "utf8");
    const { data } = matter(fileContents);

    const options = { month: "long", day: "numeric", year: "numeric" };
    const formattedDate = new Date(data.date).toLocaleDateString(
      "en-IN",
      options
    );

    const frontmatter = {
      ...data,
      date: formattedDate,
    };
    return {
      slug,
      ...frontmatter,
    };
  });

  return allPostsData.sort((a, b) => {
    if (new Date(a.date) < new Date(b.date)) {
      return 1;
    } else {
      return -1;
    }
  });
};
```

Okay so it's a good amount of code, wait until we add more to it xD, but let's understand what happened here.

First, we fetched the directory named `posts` from our root. Then with the help of node's fs package we read all the contents in the posts folder.
`allPostData` function is doing the chunk of work here -

1. First we made slug for each file in posts directory
2. We fetched the content of each file by joining the directory and filename.
3. Contents from front matter is fetched in `data`
4. We changed the date format to be visible on the index page. _You can totally skip this part_, it's not necessary.
5. We updated our frontmatter and returned slug and frontmatter to `allPostData` function
6. If you want your posts to be sorted in some way in index file, that's what we're doing next. Latest to oldest here.

Woof! So much here, but it's very much same to what you can find in Next's docs or some other articles.
Now we're ready to show the posts on our index page, so let's create one.

## 4. Creating Index of all posts

I want my blog posts route to be `/blog/post/`, so make a folder named `blog` in the pages directory and inside that, create a `index.js` file. Now when we'll start
our app `/blog` route will point to this index file.

I'll now share the code, but beware if it's your first time working with dynamic pages in Next.js, high chances that few lines will go over your head, but it's alright, I'll describe everything that's happeneing.
So, add the below content to your `./blog/index.js/` file.

```js
// ./blog/index.js

/** @jsx jsx */
import { jsx, Flex, Heading, Box, Text } from "theme-ui";
import Link from "next/link";
import { getSortedPosts } from "../../lib/posts";

const BlogIndex = ({ allPostsData }) => {
  return (
    <>
      <Box sx={{ variant: "containers.page" }}>
        <Heading>My Blog</Heading>
        <Flex
          sx={{
            flexWrap: "wrap",
            mt: "2rem",
            direction: "column",
          }}
        >
          {allPostsData.map(({ slug, date, title, excerpt }) => (
            <Box variant="containers.postCard" sx={{ my: "0.5rem" }} key={slug}>
              <li
                sx={{
                  display: "flex",
                  flexDirection: ["column", "row"],
                  my: "1rem",
                }}
              >
                <Box>
                  <Link key={slug} href="/blog/[slug]" as={`/blog/${slug}`}>
                    <a>
                      <Heading
                        sx={{
                          fontSize: "calc(1.6rem + 0.2vw)",
                          fontWeight: "500",
                        }}
                      >
                        {title}
                      </Heading>
                    </a>
                  </Link>

                  <Box sx={{ my: "0.5rem" }}>{excerpt}</Box>

                  <Text>{date}</Text>
                </Box>
              </li>
            </Box>
          ))}
        </Flex>
      </Box>
    </>
  );
};
export default BlogIndex;

export async function getStaticProps() {
  const allPostsData = getSortedPosts();
  return {
    props: {
      allPostsData,
    },
  };
}
```

So it's just the layout of the index page? How are we fetching posts here?

I've got the answers, don't worry. It's more than just the layout of index page.
First, if you're curious what are those `variants` or `sx` or that `jsx` I wrote on the top, they all are related to theme-ui and variants is how we connect that `theme.js` file we made earlier with the concerned component,
so if you're using some other UI library, you don't need to import these things.

So about fetching posts, we're importing `getSortedPosts` from `posts.js` we created in lib folder.
What this function will do is, it'll store all the posts in `allPostsData`, which then can be returned to the page above(`BlogIndex` here) just like props in a react component.

Now if you're new to Next.js, you might be asking what is this `getStaticProps` and what role is it playing here?
So in version 9.3, Next.js included `getStaticProps` and `getServerSideProps` for fetching data in the page without using any other library. And if you compare the names
you might get an idea of what do they do. `getStaticProps` fetches all the data at build time, making our website static, just like Gatsby. While `getServerSideProps` fetches data on runtime, just like many other server rendered websites.
Although both are SEO friendly, `getStaticProps` being static really adds up to the website performance. _It is the one returning props to the page above_.

Ah! so much of getStatic, getServerSide, right? Well, people like these.

Now I guess the last thing bothering you might be, "what's with the `Link` component, why it's being so weird?".
So as I said earlier, I want by posts to be on route `/blog/post-name`. We'll have a lot of posts as time will pass and we can't just make many such index components for each file, so we need **dynamic routing** here and that's how it is handled in Next.js.
First we told href that the link will be of style `/blog/[slug]` so it knows it's dynamic, and then we're telling as prop what the actual value is.

Now it's still not clear, don't worry, once we will make the page for showing full post, it'll be more clear.

For now, let's run our code to see how it looks. In your terminal, make sure you're in the directory of your project, the run this

```
npm run dev

```

This will start next server on post 3000. And once you go to `http://localhost:3000/blog`, if you see something like the image below, you're going good

![Index page for posts](https://dev-to-uploads.s3.amazonaws.com/i/ea4vdu9gw0t4hfm2ratc.png)

And if there are some troubles, maybe just contact me and I'll try my best to make it work for you.

---

So that's the end of part-1 of **Making MDX blog with Next.js**. In the next and final part, we'll discuss some common issues of handling components, front-matter and MDX, while completing this blog.