Membangun Blog menggunakan CMS (seperti WordPress atau sistem Headless via layanan third-party) memang populer. Tetapi, bagi web developer, menyimpan konten tulisan di dalam file system berbentuk Markdown (.md) di repositori GitHub adalah candu yang sempurna.
Alasannya sederhana: Anda menguasai konten 100%, sangat ringan (beban database berkurang gratis), dan sangat disukai mesin pencari (SEO).
Dalam tutorial ini, kita akan mengubah kerangka Next.js (App Router) biasa menjadi sebuah mesin blog modern. Anda akan belajar:
- Mengekstrak metadata tulisan via Frontmatter.
- Mengurai teks Markdown menjadi HTML React yang interaktif dengan
react-markdown. - Merender halaman secara statis di URL dinamis
app/[slug].
[AD_SLOT]
Persiapan Awal Sistem (Dependencies)
Mulailah di direktori root Next.js Anda. Install tiga ksatria utama:
yarn add gray-matter react-markdown remark-gfm
- gray-matter: Pengekstrak Frontmatter (Bagian konfigurasi
title,date,authordi pucuk file .md). - react-markdown: Mesin penerjemah komponen Markdown murni menjadi komponen React JSX yang mudah kita "gaya" (Styling) dengan Tailwind.
- remark-gfm: Plugin Github Flavored Markdown (mendukung tabel, centang list to-do, strikethrough).
Langkah 1: Struktur Pola Folder
Setiap aplikasi butuh landasan untuk datanya. Kita buat folder penyimpanannya. Buat folder baru di bawah root (sejajar dengan folder app dan package.json), namakan: content/blog/.
my-nextjs-app/
├── app/
│ └── [slug]/
│ └── page.tsx
├── content/
│ └── blog/
│ ├── hello-world.md
│ └── how-to-deploy.md
└── package.json
Isi hello-world.md seperti ini:
---
title: "Hello World: Postingan Baru Saya"
publishedAt: "2026-02-25T10:00:00Z"
---
Ini adalah isi *postingan* test untuk blog Markdown saya.
Berikut sebuah **kode Javascript**:
`console.log("Hello from Markdown!");`
[AD_SLOT]
Langkah 2: Mesin Pembaca Markdown Helper (lib/markdown.ts)
Kita perlu sebuah jembatan yang menghubungkan API Server bawaan Next.js dan file lokal OS kita.
Buat file lib/markdown.ts.
import fs from "fs";
import path from "path";
import matter from "gray-matter";
// Lokasi folder statik Blog kita. (Cari dengan fungsi process.cwd() nodejs)
const postsDirectory = path.join(process.cwd(), "content/blog");
/**
* 1. Mendapatkan nama sebuah artikel (slug) tanpa ekstensi .md
*/
export function getPostBySlug(slug: string) {
const realSlug = slug.replace(/\.md$/, "");
// Cari path aslinya di harddisk kita
const fullPath = path.join(postsDirectory, `${realSlug}.md`);
// Baca konten dari file tersebut sebagai string raw text
const fileContents = fs.readFileSync(fullPath, "utf8");
// Destruktur metadata dengan gray-matter. content -> Teks bebas, data -> objek JS.
const { data, content } = matter(fileContents);
return { slug: realSlug, meta: data, content };
}
/**
* 2. Mengambil SEMUA tulisan blog (Untuk Page Index)
*/
export function getAllPosts() {
const slugs = fs.readdirSync(postsDirectory);
const posts = slugs.map((slug) => getPostBySlug(slug));
// Sortir dari tulisan terbaru ke terlama
return posts.sort((post1, post2) => (
new Date(post1.meta.publishedAt) > new Date(post2.meta.publishedAt) ? -1 : 1
));
}
Langkah 3: Eksekusi Page Render (app/[slug]/page.tsx)
Inilah keajaiban App Router terbaru Next.js. Semua komponen secara default merupakan Server Component, sehingga Node.JS fs di helper yang baru kita buat, langsung bisa dipanggil di sini. Tidak perlu getStaticProps lagi!
import { notFound } from "next/navigation";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import { getPostBySlug } from "@/lib/markdown"; // impor helper sebelumnya
// Deklarasi Typing Props untuk parameter dinamis dari Next.js Router
interface ArticleProps {
params: Promise<{ slug: string }>;
}
export default async function BlogPostPage({ params }: ArticleProps) {
const resolvedParams = await params;
const slug = resolvedParams.slug;
let article;
try {
// Panggil file markdown dengan helper
article = getPostBySlug(slug);
} catch (e) {
// Bila file markdown-nya tidak ada, Redirect otomatis ke Halaman 404
notFound();
}
return (
<article className="max-w-3xl mx-auto px-6 py-20 prose prose-invert">
<header>
<h1 className="text-4xl font-bold text-white mb-4">{article.meta.title}</h1>
<time className="text-gray-400">{article.meta.publishedAt}</time>
</header>
{/* Render Markdown menajadi HTML */}
<div className="mt-10">
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{article.content}
</ReactMarkdown>
</div>
</article>
);
}
Kini navigasi ke http://localhost:3000/hello-world akan menghasilkan postingan lengkap dari Markdown!
Kesimpulan
Sistem basis data terkadang malah menghambat kreativitas penulis kecil (Over-engineering). Dengan teknik Markdown dan keangkuhan komputasi statik pahlawan Vercel (Next.js), Anda mendapat skor "Lighthouse 100", SEO jempolan, Syntax Highlight, dan kebebasan absolut. Kini hanya tinggal menyebarkan karya Anda!
