Membuat Blog dengan MDX dan Next.js

Create at : 1 Juni 2024


Table Of Content

Pendahuluan

Blog Merupakan suatu wadah untuk menuangkan ide, pemikiran, anatau untuk wadah bertukar informasi. Sebagai Developer kita bisa membuat blog dengan menggunakan berbagai macam teknologi, salah satunya adalah dengan menggunakan Next.js dan MDX.

Apa itu nextjs

Next.js merupakan project open source yang dikembangkan oleh Vercel. Next.js menggunakan React sebagai library utama untuk membangun web app, dengan menggunakan Next.js yang memiliki konsep component-based architecture memungkinkan kita untuk membangun web app dengan lebih cepat dan efisien. Lalu mengapa kita harus menggunakan Next.js? berikut beberapa alasan mengapa kita harus menggunakan Next.js:

  • Easy Routing
  • Static Site Generation
  • Server Side Rendering
  • SEO optimization

Informasi lebih lanjut mengenai Next.js bisa dilihat di sini.

Apa itu MDX?

MDX merupakan gabungan dari Markdown dan JSX, hal ini memungkinkan MDX dicompile menggunakan JSX dan memungkinkan kita untuk menambahkan komponen JSX menuju Markdown.

---
title: "Membuat Blog dengan MDX dan Next.js"
description: "This is the first blog post"
date: 2024-01-01
---

# Ini heading dari MDX
menambahkan komponen alert pada file MDX
<Component />

MDX sendiri memiliki struktur file yang mirip dengan markdown seperti contoh diatas dimana terdapat frontMatter dan main content. frontMatter bisa juga disebut dengan metadata dari suatu file, biasanya terdiri dari judul, deskripsi, tanggal, atau pengarang. Sedangakn main content merupakan isi konten dari file tersebut.

Mengapa kita harus menggunakan MDX? berikut beberapa alasan mengapa kita harus menggunakan MDX:

  • Memungkinkan kita untuk menulis komponen React di dalam Markdown.
  • Memiliki basis markdown sehingga mudah untuk digunakan.
  • Bisa melakukan customisasi sesuai kebutuhan.

Untuk lebih lengkap mengenai MDX bisa dilihat di sini.

Konfigurasi MDX

Untuk membangun blog dengan menggunakan MDX dan Next.js kita harus melakukan konfigurasi terlebih dahulu, berikut langkah-langkah yang harus dilakukan untuk melakukan konfigurasi MDX.

1. Installasi package Next.js

npx create-next-app@latest blox-mdx

cd blox-mdx

npm install

npm run dev

2. Installasi package MDX

npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx

Setelah melakukan installasi package diatas lakukan penambahan seperti dibawah ini pada file next.config.mjs .

import createMDX from "@next/mdx";

/** @type {import('next').NextConfig} */
const nextConfig = {
    // Configure `pageExtensions` to include markdown and MDX files
    pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
    // Optionally, add any other Next.js config below
};

const withMDX = createMDX({
    // Add markdown plugins here, as desired
});

// Merge MDX config with Next.js config
export default withMDX(nextConfig);

Penambahan code diatas digunakan untuk memberikan akses nextjs untuk bisa menggunakan file markdown dan mdx.

3. Install gray-matter

npm install gray-matter

Directory Structure

Setelah melakukan konfigurasi diatas kita bisa lanjut untuk membuat blog page, yang pertama dilakukan adalah buat halaman blog dan buat folder posts seperti dibawah ini. Setelah melakukan konfigurasi diatas selanjutnya buat halaman blog dengan membuat file page.tsx pada folder blog dan buat folder posts pada app directory project kemudian isi dengan 1 atau 2 dile mdx dengan struktur seperti contoh sebelumnya.

.
└── project/
    ├── app/
       └── blog/
           └── page.tsx
    └── posts/
        ├── blog-one.tsx
        └── blog-two.tsx

Fungsi untuk mendapatkan postingan blog

Sebelum membuat fungsi yang berfungsi untuk mendapatkan slug, content, dan frontMatter dari file mdx, mari kita pahami bagaimana cara mendapatkan isi (isi disini mencakup fronMatter dan main content) dari file mdx. Dengan menggunakan fungsi readdirSync dan readFileSync pada package fs kita bisa mendapatkan isi dari file mdx yang ada pada directory posts, berikut gambaran untuk lebih mudah dipahami.

readdir and readFile fs

Langkah selanjutnya adalah membuat fungsi yang berfungsi untuk mendapatkan slug, content, dan frontMatter dari file mdx yang ada pada directory posts.

import fs from "fs";
import path from "path";
import matter from "gray-matter";

export function getPosts() {
    // declare directory
    const dir = path.join(process.cwd(), "posts");
    const files = fs.readdirSync(dir);
    const contentFile = files.map((file) => {
        return fs.readFileSync(`${dir}/${file}`, "utf8");
    });
    // ...

    // get slug from name file
    const slug = files.map((file) => {
        const slug = file.replace(".mdx", "");
        return slug;
    });

    // get frontMatter and content from file and combine with slug
    let frontMatter = contentFile.map((file, id) => {
        const {content,data} = matter(file);
        return {
            frontMatter: data,
            content: content,
            slug: slug[id]
        };
    });


    return frontMatter;
}

fungsi diatas terdiri dari beberapa bagian utama diantaranya:

  1. Mendapatkan isi konten dari file mdx.
  2. Mendapatkan frontMatter dari file mdx.
  3. Mendapatkan slug dari file mdx.

Menampilkan Postingan Blog

Untuk kita dapat menampilkan postingan blog kita bisa menggunakan fungsi yang telah kita buat sebelumnya, berikut contoh code untuk mendapatkan frontMatter dan slug dari postingan blog.

    const fetchData = async () => {
        const posts  = getPosts();
        return posts ;
        // const data = props;
    };

    const files = await fetchData();

Untuk menampilkan postingan blog kita bisa melakukan mapping, menggunakan fungsi map dari js pada variabel object files, yang berisi frontMatter dan slug dari postingan yang ada pada posts directory. Kalian bisa membuat sebuah component untuk blog card, atau bisa langsung menampilkan postingan blog pada page blog. Berikut contoh code untuk menampilkan postingan blog.

// pages/blog/page.tsx

export default async function Blog() {

    const fetchData = async () => {
        const posts  = getPosts();
        return posts ;
        // const data = props;
    };

    const files = await fetchData();

    return (
        <section>
            {posts.map((post) => (
                <article key={post.slug}>
                    <h1>{post.frontMatter.title}</h1>
                    <p>{post.frontMatter.description}</p>
                    <p>{post.frontMatter.date}</p>
                </article>
            ))}
        </section>
    );
}

mapping blog files

Detail Postingan Blog

Dalam konteks pembuatan blog dengan Next.js dan MDX, [slug] directory biasanya merujuk pada parameter pada halaman dinamis yang dibuat untuk setiap postingan blog. Slug adalah bagian dari URL yang biasanya digunakan untuk mengidentifikasi sumber daya secara unik. Dalam kasus ini, slug diambil dari nama file postingan blog.

Buat folder [slug] pada folder blog, kemudian buat file page.tsx pada folder [slug] seperti dibawah ini.

.
└── project/
    ├── app/
       └── blog/
           ├── page.tsx
           └── [slug]/
               └── page.tsx
    └── posts/
        ├── blog-one.tsx
        └── blog-two.tsx

Untuk mendapatkan data postingan yang sesuai dengan slug yang diberikan, kita bisa menggunakan fungsi yang telah kita buat sebelumnya. Berikut contoh code untuk mendapatkan data postingan yang sesuai dengan slug yang diberikan.

// pages/blog/[slug]/page.tsx
import { getPosts } from "../../../lib/posts";

export default function Blog({ params }: { params: { slug: string } }) {
    const props = getPost().find((post) => post.slug === params.slug);
    //...
    if (!props) {
        return <div>Post not found</div>;
    }
    return (
        //...
            <article>
                {props.content}
            </article>
        //...
    );
}

Untuk menampilkannya kita bisa lengsung memasukkan saja menuju tag article. Namun dikarenakan content yang kita dapat masih menggunakan format mdx atau md kita harus mengkonversinya terlebih dahulu menggunakan MDXRemote. Berikut contoh code untuk menampilkan postingan blog.

// pages/blog/[slug]/page.tsx
import { MDXRemote } from "next-mdx-remote/rsc";

//...
export default function Blog({ params }: { params: { slug: string } }) {
    //...
    return (
        //...
            <article>
                <MDXRemote source={props.content} />
            </article>
        //...
    );
}

Jika fungsi diatas berjalan maka akan nampak seperti gambar dibawah ini.

blog post

Dilihat dari hasil diatas postingan berhasil ditampilkan pada halaman menggunakan MDXRemote, namun terdapat masalah pada styling yang tidak teraplikasikan dengan baik. Untuk mengaytasi hal berikut bisa menggunakan package @tailwindcss/typography dari TailwindCSS.

Pertama kita install terlabih dahulu package tersebut.

npm install -D @tailwindcss/typography

Setelah melakukan instalasi package kita tambahkan terlebih dahulu pada tailwind.config.js seperti dibawah ini.

// tailwind.config.js
module.exports = {
    //...
    plugins: [require("@tailwindcss/typography")],
};

Langkah selanjutnya ialah menambahkan class prose pada tag article pada detail konten page seperti dibawah ini. Setelah menambahkan class prose maka postingan blog akan terlihat seperti gambar dibawah ini.

// pages/blog/[slug]/page.tsx
//...
<article className="prose">
    <MDXRemote source={props.content} />
</article>
//...

blog post after prose

Dari hasil diatas masih banyak yang bisa di kembangkan lagi sesuai kebutuhan masing-masing, seperti menambahkan navigasi, menambahkan style, atau menambahkan fitur lainnya seperti Table Of Content, Input Search, dan Filter Tags.

Source

.Alfazh

Let's Get In Touch 👍

© 2024 Alfazh. All rights reserved.