How to build a blog in NextJS

Christopher Waddington

How to build a blog in NextJS

The question begins with how do you make a blog in NextJS? I've done some research and decided on using the following libraries.

  1. gray-matter
  2. marked
  3. tailwind ( for styling )

To understand how this works you need to understand NextJS Static Site Generation (SSG) and 2 specific methods:

  1. getStaticPaths
  2. getStaticProps

Let's take a look at these first

NextJS Static Site Generation (SSG)

Static Site Generation is a feature provided in the NextJS framework that allows you to pre-render pages at build time. This generates static HTML files for each page of the application and can be served directly by a web server or a CDN. With SSG, the server renders the page at build time rather than on each request to the server.

But how do I populate my pages at build time? This is where dynamic data and our 2 functions, getStaticPaths and getStaticProps come in to the picture. Dynamic data, is the idea that you can fetch data from APIs or databases during the build process then use that data to pre-render the pages. For example, you can fetch blog posts from an API and generate static blog pages with their content. In our case, instead of reading from an API, we will simply be reading from our local file structure.

getStaticPaths

This function is called in the context of the SSG at build time. It's purpose is to define that paths for which NextJS will generate static pages. During the build time, NextJS looks for components with this function defined. It then calls it to generate an array of paths based on the logic within the function. NextJS then pre-renders static pages for each path in this array. The pages are then stored and ready to be served at runtime.

Here is our getStaticPaths function:

export async function getStaticPaths() {
  const postsDirectory = path.join(process.cwd(), 'data', 'articles');
  const fileNames = fs.readdirSync(postsDirectory);

  const paths: Params[] = fileNames.map((fileName) => ({
    params: { slug: fileName.replace('.md', '') },
  }));

  return { paths, fallback: false };
}

getStaticProps

This function is also callled in the context of the SSG at build time for each each path returned in the array by getStaticPaths. When you define this function in a component, NextJS will pre-render that page with the specified data fetched at build time. For each page with this defined, it will be called and fetch the necessary data required for pre-rendering the page. This data is than passed as props to the respective page component to be rendered.

Here is our getStaticProps function:

export async function getStaticProps({ params }: { params: { slug: string } }) {
  const { slug } = params;
  const filePath = path.join(process.cwd(), 'data', 'articles', `${slug}.md`);
  const fileContent = fs.readFileSync(filePath, 'utf-8');
  const { content, data } = matter(fileContent);
  const htmlContent = marked.parse(content);  

  return { props: { content: htmlContent, data } };
}

In this function you see that we are reading fileContent using the fs library and then using matter on that content to parse out that {content, data}. We then use marked to parse the content into htmlContent. Let's talk a little about these libraries.

gray-matter

This is a JS library that is used with Markdown files (.md) to parse and extract front matter. Front matter is metatdata that is typically placed at the beginning of a .md file and provides additional information about the content such as title, slug, author, tags, date, etc. This library lets us extract that information from our articles and access it as an JS object.

marked

This is a JS library that is used for parsing and rendering Markdown content as HTML. It takes Markdown text as input and converts it into HTML markup that can be rendered in a browser. We use this to convert our articles ( which are written as a markdown file ) into HTML elements that are rendered in our <Article/> component. We then use tailwind inside our component for styling 😉

// Our Blog Page Component ( style this using Tailwind)
export default function BlogPost({ content, data }: BlogPostProps) {
  return (
    <>
        <Article title={data.title} author={data.author} content={content}/>
    </>
  );
}

Conclusion

With these elements we can create Markdown files in our data/articles folder, read and parse them using gray-matter and marked. Then use getStaticProps and getStaticPaths to pre-render them in our NextJS build. This can then be accessed via their file names at chrislikescode.com/blog/articlename. What I would like to do next is create a main blog page that can render a feed to these blogs, add in the abilitiy for people to like, comment, share ( which will require some persistence - hello mongodb 👋) and then get all this linked up in my main navigation.