Next.js Content meistern: Ein Deep Dive in statische MDX-Blogs

Cover Image for Next.js Content meistern: Ein Deep Dive in statische MDX-Blogs

Voraussetzungen

Um eine Next.js-Anwendung zu erstellen, muss Node.js auf Ihrem Rechner installiert sein. Sie können Node.js von der offiziellen Website hier herunterladen.

Erstellung einer Next.js-Blog-Anwendung

In diesem Beitrag erstellen wir eine Next.js-Blog-Anwendung mit Markdown-Unterstützung und statischer Generierung (Static Generation) zur Build-Zeit. Zunächst ist es wichtig, die Unterschiede zwischen Server-Side Rendering (SSR) und Static Generation (SG) zu verstehen.

  • Server-Side Rendering (SSR): Das HTML für eine Seite wird bei jeder Anfrage auf dem Server generiert. Das bedeutet, dass der Inhalt immer aktuell ist, aber die Ladezeit der Seite länger sein kann.
  • Static Generation (SG): Das HTML wird bereits zum Build-Zeitpunkt generiert. Dies führt zu statischen Inhalten und extrem schnellen Ladezeiten.

Diese beiden Ansätze lassen sich auch mischen: Ihr Blog kann beispielsweise einige statisch generierte Seiten und andere serverseitig gerenderte Seiten enthalten.

Lassen Sie uns nun unsere Next.js-Blog-Anwendung mit folgendem Befehl erstellen:

npx create-next-app my-next-js-blog

Wir wählen hierbei die Standardkonfiguration aus. Navigieren Sie anschließend in das neu erstellte Verzeichnis:

cd my-next-js-blog

Abhängigkeiten

Um Markdown-Unterstützung hinzuzufügen, müssen wir die folgenden Pakete installieren:

npm install gray-matter remark remark-html next-mdx-remote

Unser erster Blog-Post

Erstellen Sie ein Verzeichnis namens _posts im Stammverzeichnis Ihres Projekts und fügen Sie eine Markdown-Datei my-first-blog-post.mdx mit folgendem Inhalt hinzu:

_posts/my-first-blog-post.md
---
title: "Mein erster Blog-Post"
date: "2024-08-08"
---
 
Willkommen zu meinem ersten Blog-Artikel!

Der Bereich zwischen den --- Linien ist der sogenannte Frontmatter. Dies sind Metadaten über den Post, in diesem Fall der Titel und das Datum.

Blog-Posts aus dem Dateisystem lesen

Wir lesen die Posts zunächst direkt vom Dateisystem ein. Erstellen Sie dazu eine getPosts-Funktion in der neuen Datei src/lib/posts.ts:

src/lib/posts.ts
import fs from "fs";
import matter from "gray-matter";
import { join } from "path";
 
const postsDirectory = join(process.cwd(), "_posts");
 
export interface Post {
  title: string;
  date: string;
  content: string;
  slug: string;
}
 
export function getPostSlugs() {
  return fs.readdirSync(postsDirectory);
}
 
export function getPostBySlug(slug: string) {
  const realSlug = slug.replace(/\.mdx$/, "");
  const fullPath = join(postsDirectory, `${realSlug}.mdx`);
  const fileContents = fs.readFileSync(fullPath, "utf8");
  const { data, content } = matter(fileContents);
 
  return { ...data, slug: realSlug, content } as Post;
}
 
export function getAllPostsSortedByDate(): Post[] {
  const slugs = getPostSlugs();
  const posts = slugs
    .map((slug) => getPostBySlug(slug))
    .sort((post1, post2) => (post1.date > post2.date ? -1 : 1));
  return posts;
}

Die Blog-Posts anzeigen

Nun können wir die Posts auf der Startseite ausgeben. Erstellen Sie die Datei src/app/page.tsx:

src/app/page.tsx
import { getAllPostsSortedByDate } from "@/lib/posts";
import Link from "next/link";
 
export default function Home() {
  const posts = getAllPostsSortedByDate();
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`blog/${post.slug}`}>{post.title}</Link>
          <p>{post.date}</p>
        </li>
      ))}
    </ul>
  );
}

Einen einzelnen Blog-Post anzeigen

Erstellen Sie nun die Detailseite unter src/app/blog/[slug]/page.tsx:

src/app/blog/[slug]/page.tsx
import { MDXRemote } from "next-mdx-remote/rsc";
import { getAllPostsSortedByDate, getPostBySlug } from "@/lib/posts";
 
export async function generateStaticParams() {
  const posts = getAllPostsSortedByDate();
 
  return posts.map((post) => ({
    slug: post.slug,
  }));
}
 
const BlogPage = (props: { params: { slug: string } }) => {
  const post = getPostBySlug(props.params.slug);
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.date}</p>
      <MDXRemote
        source={post.content}
        options={{
          mdxOptions: {
            remarkPlugins: [],
            rehypePlugins: [],
          },
        }}
        components={{}}
      />
    </div>
  );
};
 
export default BlogPage;

Mit remarkPlugins und rehypePlugins können Sie den Markdown-Parser erweitern. Beliebte Plugins sind etwa remark-gfm für GitHub Flavored Markdown oder rehype-pretty-code für Syntax-Highlighting.

Wenn Sie Ihre Anwendung nun mit npm run build bauen, sehen Sie in der Ausgabe, dass die Blog-Posts statisch generiert wurden.

Route (app)                             Size     First Load JS
 /                                   6.95 kB          94 kB
 /_not-found                         871 B          87.9 kB
 /blog/[slug]                        137 B          87.2 kB
 /blog/my-first-blog-post
+ First Load JS shared by all            87 kB
 chunks/23-b75664ace61c0abb.js        31.5 kB
 chunks/fd9d1056-2821b0f0cabcd8bd.js  53.6 kB
 other shared chunks (total)          1.86 kB
 
 
  (Static)  prerendered as static content
  (SSG)     prerendered as static HTML (uses getStaticProps)

Glückwunsch! Wir haben eine Next.js-Blog-Anwendung mit MDX-Support und statischer Generierung erstellt. 🚀

Wie geht es weiter?

Nachdem Ihr Blog nun statische Seiten generiert, ist es Zeit für den nächsten Schritt:

Nächste Artikel.