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 triedgatsby
but I prefer the simplicity ofnext.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!