Projekt-Tagebuch Blog, Tag 6


coden
Rustikaler, tropischer Arbeitsplatz mit einem Laptop auf einem Holztisch, daneben eine Hängematte.
Daniel Kaser|18. April 2024
2 min.

Donnerstag, 18. April 2024

Wochen-Ziele:

  • Blog-Grundgerüst steht und ich kann bloggen bis der Arzt kommt

Tages-Ziele:

  • atemberaubende Readme erstellen

compileMDX()

Heute hab ich mir das Repo von next-mdx-remote noch mal genauer angekuckt. Insbesondere die compileMDX-Funktion. Meine Recherchen haben ergeben, dass diese Funktion neben source und options auch components empfangen kann.

Das hörte sich erst mal interessant an und ich habe es genauer unter die Lupe genommen. Und tatsächlich: Angeblich kann man hier seine Custom Components übergeben, die dann das MDX während des kompilierens mit compileMDX z.B. mit eigenen Styles anreichern können! Cool.

Also hab ich die ganze Logik wieder ein bisschen umgebaut. Jetzt kann ich tatsächlich in einem Vorgang Content von Frontmatter trennen, eigene Styles einfügen und das MDX in eine React-Komponente verwandeln. Das Ganze sieht jetzt aus wie folgt.

Meine Custom Components (Muster):

// components/CustomStyledMDX.tsx
import type { MDXComponents } from "mdx/types";

export const customComponents: MDXComponents = {
  /// Allows customizing built-in components, e.g. to add styling
  h1: ({ children }) => <h1 className="text-warning">{children}</h1>,
  h2: ({ children }) => <h2 className="text-danger">{children}</h2>,
  h3: ({ children }) => <h3 className="text-success">{children}</h3>,
};

Meine getBlogByFilePath-Funktion mit compileMDX-Funktion:

// utils/getBlogByFilePath.ts
export async function getBlogByFilePath(filePath: string): Promise<Blog> {
  const fileContent = fs.readFileSync(filePath, "utf8");
  const slug = path.parse(filePath).name;
  const { content, frontmatter } = await compileMDX<Frontmatter>({
    source: fileContent,
    options: { parseFrontmatter: true },
    components: customComponents,
  });

  return {
    frontmatter,
    content,
    slug,
  };
}

Meine SingleBlogPage-Komponente:

// src/app/blog/[slug]/page.tsx
import { notFound } from "next/navigation";
import { getBlogBySlug, getBlogs } from "../blogFetchers";

type BlogPageProps = {
  params: { slug: string };
};

export default async function SingleBlogPage({ params }: BlogPageProps) {
  const blog = await getBlogBySlug(params.slug);

  if (!blog) notFound();

  const { content, frontmatter } = blog;
  const { title, author, publishDate } = frontmatter;

  return (
    // To style MD properly, add 'prose' class
    <article className="container prose mx-auto max-w-3xl py-6 dark:prose-invert">
      <h1>{title}</h1>
      <p className="flex justify-end space-x-1">
        <span>by {author}, </span>
        <span>{publishDate}</span>
      </p>
      {content}
    </article>
  );
}

export async function generateStaticParams(): Promise<{ slug: string }[]> {
  const blogs = await getBlogs();
  return blogs.map((blog) => ({ slug: blog.slug }));
}

Dit jefällt mir schon ma janz jut!

Feedback

Schreib mir!