Als Webentwickler wollte ich schon lange einen eigenen Blog haben - nicht nur um mein technisches Wissen zu teilen, sondern auch um ehrlich über meine Erfahrungen als neurodivergenter Entwickler zu sprechen. Aber ich wollte kein WordPress oder Ghost nutzen. Ich wollte volle Kontrolle, moderne Technologie und maximale Performance.
Die Anforderungen
Bevor ich mit der Entwicklung startete, definierte ich klare Anforderungen:
- Moderne Tech-Stack: Next.js 14 mit App Router
- MDX-Support: Markdown mit React-Komponenten
- SEO-optimiert: Structured Data, Meta-Tags, Sitemaps
- Performant: Static Site Generation, optimierte Bilder
- Dark Mode: Natürlich!
- Kategorien & Tags: Flexible Content-Organisation
- Syntax Highlighting: Für Code-Beispiele
- Related Posts: Automatische Empfehlungen
Tech-Stack im Detail
Next.js 14 App Router
Der neue App Router von Next.js ist ein Game-Changer. Statt pages/ nutze ich jetzt app/ mit Server Components als Default:
// app/(marketing)/blog/[slug]/page.jsx
export async function generateStaticParams() {
const slugs = getAllPostSlugs();
return slugs.map((slug) => ({ slug }));
}
export default function BlogPostPage({ params }) {
const post = getPostBySlug(params.slug);
return <MDXRemote source={post.content} />;
}
Vorteile:
- Automatisches Code-Splitting
- Bessere Performance durch Server Components
- Einfachere Metadaten-Generierung mit
generateMetadata()
MDX mit next-mdx-remote
MDX erlaubt mir, React-Komponenten direkt in Markdown zu nutzen. Perfekt für interaktive Blog-Posts!
pnpm add next-mdx-remote gray-matter remark-gfm rehype-highlight
Die Konfiguration ist einfach:
import { MDXRemote } from 'next-mdx-remote/rsc';
import remarkGfm from 'remark-gfm';
import rehypeHighlight from 'rehype-highlight';
const mdxOptions = {
mdxOptions: {
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeHighlight],
},
};
<MDXRemote source={content} options={mdxOptions} />
File-Based Content Management
Alle Blog-Posts liegen als .mdx-Dateien in content/blog/:
content/blog/
├── nextjs-blog-mit-mdx.mdx
├── adhs-und-coding.mdx
└── hochsensibel-als-developer.mdx
Jeder Post hat Frontmatter-Metadaten:
---
title: "Mein Titel"
description: "Eine kurze Beschreibung"
date: "2024-12-14"
category: "Webentwicklung & Technik"
tags: ["Next.js", "React"]
published: true
---
Mit gray-matter parse ich das Frontmatter:
import matter from 'gray-matter';
import fs from 'fs';
export function getPostBySlug(slug) {
const fileContents = fs.readFileSync(`content/blog/${slug}.mdx`, 'utf8');
const { data, content } = matter(fileContents);
return {
slug,
content,
frontmatter: data
};
}
SEO-Optimierung
Structured Data
Jeder Blog-Post hat Schema.org BlogPosting Markup:
const structuredData = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: frontmatter.title,
description: frontmatter.description,
datePublished: frontmatter.date,
author: {
'@type': 'Person',
name: frontmatter.author,
},
};
Dynamische Metadaten
Mit generateMetadata() im App Router:
export async function generateMetadata({ params }) {
const post = getPostBySlug(params.slug);
return {
title: `${post.frontmatter.title} | Blog`,
description: post.frontmatter.description,
openGraph: {
title: post.frontmatter.title,
description: post.frontmatter.description,
type: 'article',
publishedTime: post.frontmatter.date,
},
};
}
Performance-Features
Static Site Generation
Alle Blog-Posts werden zur Build-Time generiert:
export async function generateStaticParams() {
const slugs = getAllPostSlugs();
return slugs.map((slug) => ({ slug }));
}
Ergebnis: Instant Page Loads mit 0ms Server Response Time!
Code-Splitting
Jede Route wird automatisch gesplittet. Der Blog-Code wird nur geladen, wenn du /blog besuchst.
Optimierte Bilder
Mit Next.js <Image> Component (später implementiert):
import Image from 'next/image';
<Image
src={frontmatter.image}
alt={frontmatter.title}
width={1200}
height={630}
priority={featured}
/>
Related Posts Algorithm
Ich habe einen simplen Score-basierten Algorithmus:
export function getRelatedPosts(slug, limit = 3) {
const currentPost = getPostBySlug(slug);
let relatedPosts = getAllPosts().filter(post => post.slug !== slug);
relatedPosts = relatedPosts.map(post => {
let score = 0;
// Gleiche Kategorie = +10 Punkte
if (post.frontmatter.category === currentPost.frontmatter.category) {
score += 10;
}
// Gemeinsame Tags = +5 Punkte pro Tag
const sharedTags = post.frontmatter.tags.filter(tag =>
currentPost.frontmatter.tags.includes(tag)
);
score += sharedTags.length * 5;
return { ...post, score };
});
return relatedPosts
.sort((a, b) => b.score - a.score)
.slice(0, limit);
}
Was ich gelernt habe
1. App Router > Pages Router
Der neue App Router macht so vieles einfacher:
- Layouts sind endlich vernünftig
- Server Components als Default = Performance-Boost
- Metadata-Handling ist cleaner
2. MDX ist perfekt für Blogs
Die Kombination aus Markdown-Einfachheit und React-Power ist genial:
- Schreiben ist schnell (Markdown)
- Interaktivität wo nötig (React-Komponenten)
- Type-Safety mit TypeScript möglich
3. File-Based CMS reicht oft
Ich brauche kein Headless CMS für meinen Blog:
- Git als Version Control
- VS Code als Editor
- Kein Backend nötig
- Volle Kontrolle
Nächste Schritte
Das Blog-System ist jetzt live, aber ich plane noch:
- Newsletter-Integration (Mailchimp oder ConvertKit)
- Kommentare (Giscus mit GitHub Discussions)
- View Counter (Edge Function + KV Store)
- RSS Feed (automatisch generiert)
- Search (Algolia oder Fuse.js)
Fazit
Ein modernes Blog mit Next.js und MDX aufzubauen war einfacher als gedacht. Die Developer Experience ist fantastisch, die Performance ist top, und ich habe volle Kontrolle über meine Inhalte.
Wenn du auch überlegst, einen technischen Blog zu starten: Tu es! Nicht nur für andere, sondern auch für dich selbst. Ich habe beim Schreiben dieses Posts mehr gelernt als beim reinen Coden.
Du möchtest auch so ein Blog-System? Ich entwickle moderne, performante Websites mit Next.js, React und Tailwind CSS. Lass uns sprechen!