Logo spelled as T D

A Hasty, Simple Blog Development with Next.js and MDX

Jul 10, 2020 | Thirafi Dide

It's been a while that I want to build a blog and start writing. I often have some ideas, although most of the time it just a random, unimportant idea. Nonetheless, I just want to write it and share it somewhere.

I have done several attempts to build a blog, but I was too perfectionist to finish it. I went too deep in choosing the right tech stack, managing design system and component libraries, perfecting the code snippet preview, and so on. I was caught in the trap of over-engineering, just for a simple blog. In the end, I never like the result and abandon the project.

Recently, I have taken the IELTS Test. It went kinda fine, I guess. I get to pass the score that I needed, but looking at the result, my writing (and speaking) is way below my listening and reading. This made me look back at the idea of a blog. It would be a good exercise to improve my English!

In the end, I force myself to build a simple blog. I set aside my overachieving quest for the perfect codebase, and drag myself to build a minimal, working blog.

The main tech that I use

Here the tech that I use to build and ship this blog as soon as possible:

  • Next.js because I am way more familiar with this than any other popular static-side generator. Next.js is simple enough to quickly develop a simple blog, but can be a powerful framework if I need to. I tried gatsby but I prefer the simplicity of next.js

  • MDX because I want to write my blog with markdown and insert custom components if I need it. On the plus side, it is officially supported by next.js via a small plugin @next/mdx

Even though I'm a strong advocate of strong type system, I even write all the codes in vanilla javascript! I set aside Typescript for now just so I can ship this as soon as possible.

Next.js / MDX

With @next/mdx, wiring MDX with next.js is a trivial matter. I only need to set up next.config.js to use the plugin and configure it to allow .mdx file as a page component;

// next.config.js

const withMDX = require('@next/mdx')({
	extension: /\.mdx?$/,
});

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

For now, I don't need separate layout between post pages and homepage, so I can set up the common layout for all pages via _app.js.

import UITopbar from '../src/blog-common/UITopbar';

import '../styles/global.css';

function App({ Component, pageProps }) {
	return (
		<>
			<UITopbar />

			{/* Of course you can put this into separate css if you want */}
			<div style={{ maxWidth: 600, margin: '0 auto', padding: '0px 16px' }}>
				<Component {...pageProps} />
			</div>
		</>
	);
}

export default App;

Getting the list of all posts

I put all my blog post in pages/blog directory, each as a single .mdx file. But then, I need to get the list of all posts to show it in the homepage. I sure don't want to manually maintain a single JSON just for post list. I can make a generator for it, but I'm too lazy to build one 🙃. If only I can import all the post and get metadata for each file...

And sure we can! I use babel-plugin-import-glob-array to get all the post as a list. For each post, I export a meta object to hold information that I can easily access.

// test-post.mdx
export const meta = {
  date: '2020-07-10',
  description: 'Just a simple blogpost for a test!',
  title: 'A Dummy Blog Post',
};

# A Dummy Blog Post

So this is just a dummy, but then ...

And import all the post as a list!

import { meta as metadata, _importMeta as postPaths } from './blog/*';

export default function IndexPage() {
  const posts = metadata
    .map((post, i) => ({
      ...post,
      path: postPaths[i]?.importedPath,
    }))
    .sort((postA, postB) => postB.date.localeCompare(postA.date));

  // post: Array<{ title, description, date, path }>
  // sorted by the post date!

  // ...

Design

I just want to make it look bearable, so I just do a minimal effort on this side. The only thing that I want for the design is for Teal/Blue as the accent colour. I use Coolors and hit spacebar multiple times until one of the colours shows teal. I lock that particular colour and then spam spacebar again until I get a nice colour palette.

I use Libre Franklin (for the heading) and Libre Baskerville (for the body text) fonts pairing. I am taking those from a Google Font's featured article.

For the styling, I use the good ol' CSS Modules to modularise the CSS. I also have a global.css with element selector to style the markdown result.

Code snippet

As most of the time my blog post is about frontend and other programming, I need to add syntax highlighting for the code snippets that scattered across the posts. I use rehype-highlight plugin and atom-one-light for the theme. I just add the plugin to the config and copy the theme.

// next.config.js
const highlight = require('rehype-highlight');
const withMDX = require('@next/mdx')({
	extension: /\.mdx?$/,
	options: {
		rehypePlugins: [highlight],
	},
});

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

Deployment

I use Vercel for deployment. It's super simple, especially for next.js project. What I need is to host the codebase into github, add build script in my package.json, and import the repo as my project in Vercel. Now it will automatically deploy into production whenever I push something into master.

And that's it! Of course, there are many other features that I'd like to add to my blog. Hopefully, I will add more improvements over time, like RSS and dark mode.

Until then, thanks for reading this!