How to Build a Static Blog Site

In this React tutorial, we’ll build a simple, static website for a blog using the React framework Next.js, learn how to make use of static resources in Markdown files, and then use that to present blog posts for our project site.


Building a Static Blog Site
For front-end developers, the wonderful server-side rendering (SSR) framework Next.js can be a powerful addition to the toolbox. Next.js provides an easy way to build a website that will have static content, such as a portfolio or blog site. gjstatic Right out of the box, Next.js has great website building tools, including a workflow routing system and a webpack to automatically build bundles behind the scenes so we can focus on content from the very start.

For this React tutorial, we’ll build a static blog site. Because the pages on our site won’t change often, there’s no need for a database to store posts; instead, we’ll store the posts statically in source code using Markdown and Next.js.

We’ll use these packages in our project:

• React: Declarative JS library for UI

• Next.js: Isomorphic React on the server and the browser

• Material-UI: Gorgeous, out-of-the-box UI design

• MDX: “JSX in Markdown for ambitious projects”

You’ll find the source code repository for this project available here.


React Tutorial: Getting Started
1. First, we’ll create a new directory for our project, initializing a package.json file and then install the React and Next.js packages:

mkdir blog-next
cd blog-next
npm init -y
npm install –save react react-dom next
2. Next.js has its own built-in router system ready to use, so we just need to create a pages directory:

mkdir pages
We’ll add new pages as React JSX components as we build more of the website.

3. Continuing with the component library picked option (Material-UI), install the library:

yarn add @material-ui/core
Now we’re ready to build the layout and new components with Material Design.



Creating the Website Layout
The layout for our website includes a navbar with:

• The mail link to home (title)

• An “About” link

• A section title for Feature Blog posts

• A two-column grid displaying cards with the title, date of publication and a summary of the content for each post


Layout for website


1. Define /pages/index.jsx. That will also be our landing page at, where my-domain is the domain for production, or simply localhost:3000 if we are in development.

2. Define the index page as follows:

const Index = () =>
const classes = useStyles();
return (
<CssBaseline />
<Header />
<Container maxWidth=”lg” className=classes.container>
<Box my=4 display=”flex” justifyContent=”center”>
<Typography variant=”h4″ component=”h1″ gutterBottom>
Featured Blog posts
<Grid container spacing=4> => (
<PostCard key=post.title post=post />
<Footer title=”My Blog” description=”Hi there, this is my blog!” />
Here we’re using several components inside the /components directory, such as Header for the top navigation panel, and Footer for the bottom panel. These components are relatively small and straightforward; you can take a look at these components at my github repo.

The third component, PostCard, and the imported array blogPosts, deserve a closer look, because they are the core elements of the micro-blog engine.

Let’s take a look at PostCard.jsx first:

const PostCard = ( post ) =>
const classes = useStyles();
return (
<Grid item xs=12 md=6>
<Link href=post.path>
<Card className=classes.card>
<div className=classes.cardDetails>
<Typography component=”h2″ variant=”h5″>
<Typography variant=”subtitle1″ color=”textSecondary”>
<Typography variant=”subtitle1″ paragraph>
<Typography variant=”subtitle1″ color=”primary”>
Continue reading…

This is a component that expects a prop post that contains a title, publish date, path, or href and summary, as we can see in the layout example above.


Setting Up Markdown Configuration in Next.js
We must somehow provide these properties from the blog posts we write in Markdown—that is, inside the pages directory—to the PostCard component so that we can display a preview on the land page. How? The answer is that because our site is static, we can just read the properties from the file system!

But first, we must install and configure the package we’ll use to work with Markdown: MDX, which comes ready to work with Next.js.

1. Add next and a plug-in for Next.js:

yarn add @next/mdx @mdx-js/loader
2. Then create file /next.config.js and include these contents:

const withMDX = require(‘@next/mdx’)(
extension: /\.mdx?$/

module.exports = withMDX(
pageExtensions: [‘js’, ‘jsx’, ‘md’, ‘mdx’]
This tells Next to automatically import files with the ‘md’ extension and process them as if they were JSX files. We’ll see that our post is actually both a JSX React component and a Markdown file at the same time.


Importing Markdown Posts Inside React
Now we define the JavaScript utility to load the posts in Markdown.

1. Create the folder /data and inside the file get-blog-posts.js:

const fs = require(‘fs’);
const path = require(‘path’);

const META = /export\s+const\s+meta\s+=\s+(\.)*?\n\)/;
const DIR = path.join(process.cwd(), ‘./pages/blog/’);
const files = fs
.filter((file) => file.endsWith(‘.md’));

module.exports = files
.map(file => {
const name = path.join(DIR, file);
const contents = fs.readFileSync(name, ‘utf8’);
const match = META.exec(contents);

if (!match || typeof match[1] !== ‘string’)
throw new Error(`$name needs to export const meta = {}`);

const meta = eval(‘(‘ + match[1] + ‘)’);

path: ‘/blog/’ + file.replace(/\.mdx?$/, ”)
.filter((meta) => meta.published)
.sort((a, b) => new Date(b.publishedAt) – new Date(a.publishedAt));
This function looks inside the folder /pages/blog/ for any file with extension .md. Inside each file, it expects an object called meta, where the properties of the post reside (title, path, summary, and publish date), which is what the function exports in the end.

Let’s see what a blog post looks like:

import BlogPost from ‘../../components/BlogPost’;

export const meta =
published: true,
publishedAt: ‘2019-01-15’,
title: ‘This is my very first blog post’,
‘I am learning how to build a blog using Markdown in a static web page build on top of Next.js’

export default ( children ) => <BlogPost meta=meta>children</BlogPost>;

<<Actual contents go here>>
The example above is the first part of a post at /pages/blog/ (note that I added a sub dir blog inside pages, to keep the posts apart from the other pages). It starts by importing a React component BlogPost, which is the frame for the contents of the blog, as we’ll see shortly. Then we have the meta-object with the meta-data of the blog post, and a default export of this JSX file (a React component). Finally, we have the post content! That’s how we write a post in our blog. It’s so simple and neat!


Handling Static Resources
Returning to our preview of the posts on the index page, we should be able to import the meta-data and display it in the cards.

However, we must find a way, since we’re working with static data, to have the import happen at compile-time. A regular import won’t work because, when it’s executed in the browser, it will try to bring data up that is in the server. The solution is to pre-evaluate the contents given by get-blog-posts.js in the server, before they’re served to the client.

1. To do this, we’ll use a few plugins available in babel: babel-plugin-macros and babel-plugin-preval:

yarn add –dev babel-plugin-macros babel-plugin-preval
2. Add a file .babelrc and the contents:

“presets”: [“next/babel”],
“plugins”: [“macros”]

3. Add a file at /data/blog-posts.js (this is where the magic happens!):

import preval from “babel-plugin-preval/macro”;

module.exports = preval`module.exports = require(‘./get-blog-posts.js’);`;
The last line pre-evaluates the contents retrieved by get-blog-posts.js, so we are really exporting the array of meta-objects instead of the function to fetch them.


Displaying a Blog Post as a Stand-alone Page
Finally, let’s see how a blog post displays:

Static Blog Site

We see:

Leave a Reply

Your email address will not be published. Required fields are marked *