Wie ein Blogbereich zu einer bestehenden Next.js-Homepage hinzugefügt wurde, mit MDX für einfache und flexible Inhaltserstellung.
In diesem Artikel wird beschrieben, wie ein Blogbereich zur bestehenden Next.js-Homepage hinzugefügt wurde. Zur Verwaltung der Blogposts kommen dabei Markdown-Dateien (MDX) zum Einsatz, was eine einfache und flexible Möglichkeit bietet, Inhalte zu erstellen und zu bearbeiten.
Um MDX-Dateien in unsere Next.js-Anwendung zu integrieren, habe ich die folgenden Pakete verwendet:
In der next-config.mjs habe ich withMDX hinzugefügt, um die MDX-Integration zu konfigurieren.
code-snippet.ts
import createMDX from '@next/mdx' /** * @type {import('next').NextConfig} */ const nextConfig = { ... pageExtensions: ['mdx', 'md', 'tsx', 'ts'], ... }; const withMDX = createMDX({ // Add markdown plugins here, as desired }); export default withMDX(nextConfig);
Zuerst habe ich eine Datei mdx-component.tsx erstellt, um benutzerdefinierte MDX-Komponenten zu definieren.
code-snippet.ts
import type { MDXComponents } from "mdx/types"; export function useMDXComponents(components: MDXComponents): MDXComponents { return { ...components, }; }
In der Datei mdxUtils.ts habe ich Funktionen zum Verwalten der MDX-Dateien erstellt. Diese Funktionen helfen dabei, den Pfad zu den Posts zu bekommen und alle MDX-Dateien im Verzeichnis posts zu finden.
code-snippet.ts
import { readdir } from "fs/promises"; import path from "path"; /** * Useful when you want to get the path to a specific file */ export const POSTS_PATH = path.join(process.cwd(), "posts"); /** * The list of all mdx files inside the POSTS_PATH directory */ export async function getPostFilePaths() { const paths = await readdir(POSTS_PATH); // Only include md(x) files return paths.filter((path) => /\.mdx?$/.test(path)); }
In der Datei app/posts/page.tsx habe ich eine Übersichtsseite erstellt, die alle gefundenen Markdown-Artikel als Karten auflistet und zum Weiterlesen verlinkt.
code-snippet.ts
import { getPostFilePaths, POSTS_PATH } from "../../utils/mdxUtils.ts"; interface Post { filePath: string; data: { title: string; description: string; image: string; author: string; date: string; }; content: string; } async function getData(): Promise<{ posts: Post[] }> { const postFilePaths = await getPostFilePaths(); const posts = await Promise.all( postFilePaths.map(async (filePath) => { const source = await readFile(path.join(POSTS_PATH, filePath)); const { content, data } = matter(source); return { content, data, filePath, } as Post; }) ); return { posts }; } const Posts: React.FC = () => { const { posts } = React.use(getData()); return ( <> ... <Box sx={{ display: "grid", gap: 4, gridTemplateColumns: { md: "1fr 1fr 1fr", sm: "1fr 1fr", xs: "1fr", }, }} > {posts .sort( (a, b) => new Date(b.data.date).getTime() - new Date(a.data.date).getTime(), ) .map((post) => ( <Link key={post.filePath} as={`/posts/${post.filePath.replace(/\.mdx?$/, "")}`} href={`/posts/[slug]`} style={{ textDecoration: "none", }} > ... </Link> ))} </Box> ... </> ); }; export default Posts;
Schließlich wird jeder Blogpost über die Datei app/posts/[slug]/page.tsx gerendert.
code-snippet.ts
import { MDXRemote } from "next-mdx-remote/rsc"; import { POSTS_PATH } from "../../../utils/mdxUtils.ts"; import matter from "gray-matter"; import type { MDXRemoteProps } from "next-mdx-remote/rsc"; const components: MDXRemoteProps["components"] = { h1: (props) => <Typography variant="h1">{props.children}</Typography>, h2: (props) => <Typography variant="h2">{props.children}</Typography>, h3: (props) => <Typography variant="h3">{props.children}</Typography>, h4: (props) => <Typography variant="h4">{props.children}</Typography>, p: (props) => ( <Typography variant="body1" gutterBottom> {props.children} </Typography> ), }; const Posts: React.FC<{ params: { slug: string } }> = ({ params: { slug }, }) => { const postFilePath = path.join(POSTS_PATH, `${slug}.mdx`); const source = fs.readFileSync(postFilePath); const { data } = matter(source); return ( <> <Hero title={data.title} subtitle={data.description} image={data.image} /> <Block> <MDXRemote components={components} source={source} options={{ parseFrontmatter: true, }} /> </Block> </> ); }; export default Posts;
Mit dieser Implementierung können wir neue Blogposts hinzufügen und verwalten, indem wir einfach neue MDX-Dateien im posts Verzeichnis erstellen. Das System ermöglicht es uns, die Inhalte klar strukturiert und ansprechend zu präsentieren. Next.js bietet dabei die notwendige Flexibilität und Leistung, um auch größere Mengen an Inhalten effizient zu verwalten.