tutorial

Cara Membuat Blog Statis (Markdown) di Next.js 14 Secara Lengkap

Irfannur Diah
Jadi.pw Creator
Cara Membuat Blog Statis (Markdown) di Next.js 14 Secara Lengkap

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:

  1. Mengekstrak metadata tulisan via Frontmatter.
  2. Mengurai teks Markdown menjadi HTML React yang interaktif dengan react-markdown.
  3. 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, author di 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!

Irfannur Diah

Ditulis olehIrfannur Diah

Kreator independen yang mendedikasikan waktunya untuk membangun alat, membagikan insight, dan membantu ekosistem kreator lokal bertumbuh lebih independen.

Percepat Kerja Anda Hari Ini

Eksplorasi koleksi template, source code, dan sistem produksi siap pakai dari jadi.pw. Hemat ratusan jam kerja pengembangan dan langsung fokus pada pertumbuhan bisnis Anda.

Dapatkan update artikel, rilisan source code baru, dan diskon eksklusif. Tanpa spam.