Next.js Markdown blog

Next.js is a great React framework. It's easy to use and lightweight. I use it on my personal website (toukopeltomaa.com).

In this post I'm going to show how to make a simple blog using Markdown and Next.js.

1. Create folder for all Markdown files

Create a folder named posts root of your project. Create all of your posts as Markdown there

Example Markdown file in posts/example-post.md

---
title: Example post
date: 13-11-2018
writtenBy: Touko Peltomaa
---

## Example post

2. Add Webpack plugin raw-loader to next.config.js

We need raw-loader to load Markdown files

npm i -D raw-loader

next.config.js file

Create next.config.js to your project's root folder if you haven't already

module.exports = {
  webpack: (config) => {
    config.module.rules.push({
      test: /\.md$/,
      use: "raw-loader",
    });

    return config;
  },
};

3. Create home page at pages/index.js

Parse posts

We are going to parse posts with gray-matter library

gray-matter library will parse the YAML metadata. We can use the YAML data for SEO, written by and post dates.

npm i -S gray-matter

Gets posts from posts/* folder

import React from "react";
import matter from "gray-matter";
import Link from "next/link";

export default class extends React.Component {
  static async getInitialProps() {
    // Get posts from folder
    const posts = ((ctx) => {
      const keys = ctx.keys();
      const values = keys.map(ctx);

      const data = keys.map((key, index) => {
        // Create slug from filename
        const slug = key
          .replace(/^.*[\\\/]/, "")
          .split(".")
          .slice(0, -1)
          .join(".");
        const value = values[index];

        // Parse document
        const document = matter(value);

        return {
          document,
          slug,
        };
      });

      return data;
    })(require.context("../posts", true, /\.md$/));

    return {
      posts,
    };
  }

  render() {
    return (
      <>
        <h1>Posts</h1>
        {this.props.posts.map(({ document: { data }, slug }) => (
          <Link href={{ pathname: "/post", query: { id: slug } }} key={slug}>
            <h2>{data.title}</h2>
          </Link>
        ))}
      </>
    );
  }
}

The getInitialProps function gets posts from posts folder and returns them in a usable format. We are going to use your filename as our post's slug or id

3. Create post page at pages/post.js

Get document name from querystring, require it and parse it.

Install React Markdown

To render Markdown we are going to use react-markdown

npm i -S react-markdown
import React from "react";
import matter from "gray-matter";
import ReactMarkdown from "react-markdown";

export default class extends React.Component {
  static async getInitialProps({ query }) {
    const post = await import(`../posts/${query.id}.md`);
    const document = matter(post.default);

    return {
      ...document,
    };
  }

  render() {
    return (
      <>
        <h1>{this.props.data.title}</h1>
        <i>{`Written by ${this.props.data.writtenBy} | ${this.props.data.date}`}</i>
        <ReactMarkdown source={this.props.content} />
      </>
    );
  }
}