MDX

Markdown ist eine leichtgewichtige Auszeichnungssprache zur Textformatierung. Sie ermöglicht das Schreiben mit einfacher Text-Syntax und die Konvertierung in strukturell valides HTML. Es wird häufig für das Verfassen von Inhalten auf Websites und Blogs verwendet.

Sie schreiben...

I **love** using [Next.js](https://nextjs.org/)

Ausgabe:

<p>I <strong>love</strong> using <a href="https://nextjs.org/">Next.js</a></p>

MDX ist eine Erweiterung von Markdown, die es Ihnen ermöglicht, JSX direkt in Ihren Markdown-Dateien zu verwenden. Es ist eine leistungsstarke Methode, um dynamische Interaktivität hinzuzufügen und React-Komponenten in Ihre Inhalte einzubetten.

Next.js unterstützt sowohl lokale MDX-Inhalte innerhalb Ihrer Anwendung als auch remote MDX-Dateien, die dynamisch auf dem Server abgerufen werden. Das Next.js-Plugin übernimmt die Transformation von Markdown und React-Komponenten in HTML, einschließlich der Unterstützung für die Verwendung in Server Components (Standard im App Router).

@next/mdx

Das @next/mdx-Paket wird verwendet, um Next.js so zu konfigurieren, dass es Markdown und MDX verarbeiten kann. Es bezieht Daten aus lokalen Dateien, sodass Sie Seiten mit der Erweiterung .mdx direkt in Ihrem /pages- oder /app-Verzeichnis erstellen können.

Lassen Sie uns durchgehen, wie MDX mit Next.js konfiguriert und verwendet wird.

Erste Schritte

Installieren Sie die benötigten Pakete, um MDX zu rendern:

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

Aktualisieren Sie die Datei next.config.js im Stammverzeichnis Ihres Projekts, um die Verwendung von MDX zu konfigurieren:

next.config.js
const withMDX = require('@next/mdx')()

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Konfigurieren Sie `pageExtensions`, um MDX-Dateien einzuschließen
  pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
  // Optional: Fügen Sie weitere Next.js-Konfigurationen hinzu
}

module.exports = withMDX(nextConfig)

Erstellen Sie dann eine neue MDX-Seite im /pages-Verzeichnis:

  your-project
  ├── pages
  │   └── my-mdx-page.mdx
  └── package.json

Jetzt können Sie Markdown verwenden und React-Komponenten direkt in Ihrer MDX-Seite importieren:

import { MyComponent } from 'my-components'

# Willkommen auf meiner MDX-Seite!

Dies ist ein **fetter** und _kursiver_ Text.

Dies ist eine Liste in Markdown:

- Eins
- Zwei
- Drei

Sehen Sie sich meine React-Komponente an:

<MyComponent />

Wenn Sie zur Route /my-mdx-page navigieren, sollte Ihr gerenderter MDX-Inhalt angezeigt werden.

Remote MDX

Wenn Ihre Markdown- oder MDX-Dateien oder -Inhalte an einem anderen Ort gespeichert sind, können Sie sie dynamisch auf dem Server abrufen. Dies ist nützlich für Inhalte, die in einem separaten lokalen Ordner, einem CMS, einer Datenbank oder anderswo gespeichert sind.

Es gibt zwei beliebte Community-Pakete für das Abrufen von MDX-Inhalten:

Gut zu wissen: Bitte gehen Sie vorsichtig vor. MDX wird in JavaScript kompiliert und auf dem Server ausgeführt. Sie sollten MDX-Inhalte nur aus einer vertrauenswürdigen Quelle abrufen, da dies sonst zu Remote-Code-Ausführung (RCE) führen kann.

Das folgende Beispiel verwendet next-mdx-remote:

import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote'

interface Props {
  mdxSource: MDXRemoteSerializeResult
}

export default function RemoteMdxPage({ mdxSource }: Props) {
  return <MDXRemote {...mdxSource} />
}

export async function getStaticProps() {
  // MDX-Text - kann aus einer lokalen Datei, Datenbank, CMS, Fetch usw. stammen...
  const res = await fetch('https:...')
  const mdxText = await res.text()
  const mdxSource = await serialize(mdxText)
  return { props: { source: mdxSource } }
}
import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'

export default function RemoteMdxPage({ mdxSource }) {
  return <MDXRemote {...mdxSource} />
}

export async function getStaticProps() {
  // MDX-Text - kann aus einer lokalen Datei, Datenbank, CMS, Fetch usw. stammen...
  const res = await fetch('https:...')
  const mdxText = await res.text()
  const mdxSource = await serialize(mdxText)
  return { props: { source: mdxSource } }
}

Wenn Sie zur Route /my-mdx-page-remote navigieren, sollte Ihr gerenderter MDX-Inhalt angezeigt werden.

Layouts

Um ein Layout um MDX-Seiten zu teilen, erstellen Sie eine Layout-Komponente:

export default function MdxLayout({ children }: { children: React.ReactNode }) {
  // Erstellen Sie hier gemeinsame Layouts oder Stile
  return <div style={{ color: 'blue' }}>{children}</div>
}
export default function MdxLayout({ children }) {
  // Erstellen Sie hier gemeinsame Layouts oder Stile
  return <div style={{ color: 'blue' }}>{children}</div>
}

Importieren Sie dann die Layout-Komponente in die MDX-Seite, umschließen Sie den MDX-Inhalt mit dem Layout und exportieren Sie ihn:

import MdxLayout from '../components/mdx-layout'

# Willkommen auf meiner MDX-Seite!

export default function MDXPage({ children }) {
  return <MdxLayout>{children}</MdxLayout>;

}

Remark- und Rehype-Plugins

Sie können optional remark- und rehype-Plugins bereitstellen, um den MDX-Inhalt zu transformieren.

Beispielsweise können Sie remark-gfm verwenden, um GitHub Flavored Markdown zu unterstützen.

Da das remark- und rehype-Ökosystem nur ESM unterstützt, müssen Sie next.config.mjs als Konfigurationsdatei verwenden.

next.config.mjs
import remarkGfm from 'remark-gfm'
import createMDX from '@next/mdx'

/** @type {import('next').NextConfig} */
const nextConfig = {
  // Konfigurieren Sie `pageExtensions`, um MDX-Dateien einzuschließen
  pageExtensions: ['js', 'jsx', 'mdx', 'ts', 'tsx'],
  // Optional: Fügen Sie weitere Next.js-Konfigurationen hinzu
}

const withMDX = createMDX({
  // Fügen Sie hier gewünschte Markdown-Plugins hinzu
  options: {
    remarkPlugins: [remarkGfm],
    rehypePlugins: [],
  },
})

// MDX-Konfiguration mit Next.js-Konfiguration zusammenführen
export default withMDX(nextConfig)

Frontmatter

Frontmatter ist eine YAML-ähnliche Schlüssel/Wert-Paarung, die verwendet werden kann, um Daten über eine Seite zu speichern. @next/mdx unterstützt Frontmatter nicht standardmäßig, obwohl es viele Lösungen gibt, um Frontmatter zu Ihren MDX-Inhalten hinzuzufügen, wie z.B.:

Um Seitenmetadaten mit @next/mdx zuzugreifen, können Sie ein Meta-Objekt aus der .mdx-Datei exportieren:

export const meta = {
  author: 'John Doe',
}

# Meine MDX-Seite

Benutzerdefinierte Elemente

Ein angenehmer Aspekt der Verwendung von Markdown ist, dass es auf native HTML-Elemente abgebildet wird, was das Schreiben schnell und intuitiv macht:

Dies ist eine Liste in Markdown:

- Eins
- Zwei
- Drei

Das obige Beispiel generiert das folgende HTML:

<p>Dies ist eine Liste in Markdown:</p>

<ul>
  <li>Eins</li>
  <li>Zwei</li>
  <li>Drei</li>
</ul>

Wenn Sie Ihre eigenen Elemente für ein individuelles Erscheinungsbild Ihrer Website oder Anwendung gestalten möchten, können Sie Shortcodes verwenden. Dies sind Ihre eigenen benutzerdefinierten Komponenten, die auf HTML-Elemente abgebildet werden.

Erstellen Sie dazu eine Datei mdx-components.tsx im Stammverzeichnis Ihrer Anwendung (dem übergeordneten Ordner von pages/ oder src/) und fügen Sie benutzerdefinierte Elemente hinzu:

import type { MDXComponents } from 'mdx/types'
import Image from 'next/image'

// Diese Datei ermöglicht es Ihnen, benutzerdefinierte React-Komponenten
// für die Verwendung in MDX-Dateien bereitzustellen. Sie können jede
// React-Komponente importieren und verwenden, einschließlich Inline-Stilen,
// Komponenten aus anderen Bibliotheken und mehr.

export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    // Ermöglicht die Anpassung integrierter Komponenten, z.B. zum Hinzufügen von Stilen.
    h1: ({ children }) => <h1 style={{ fontSize: '100px' }}>{children}</h1>,
    img: (props) => (
      <Image
        sizes="100vw"
        style={{ width: '100%', height: 'auto' }}
        {...props}
      />
    ),
    ...components,
  }
}
import Image from 'next/image'

// Diese Datei ermöglicht es Ihnen, benutzerdefinierte React-Komponenten
// für die Verwendung in MDX-Dateien bereitzustellen. Sie können jede
// React-Komponente importieren und verwenden, einschließlich Inline-Stilen,
// Komponenten aus anderen Bibliotheken und mehr.

export function useMDXComponents(components) {
  return {
    // Ermöglicht die Anpassung integrierter Komponenten, z.B. zum Hinzufügen von Stilen.
    h1: ({ children }) => <h1 style={{ fontSize: '100px' }}>{children}</h1>,
    img: (props) => (
      <Image
        sizes="100vw"
        style={{ width: '100%', height: 'auto' }}
        {...props}
      />
    ),
    ...components,
  }
}

Vertiefung: Wie wird Markdown in HTML transformiert?

React versteht Markdown nicht nativ. Der Markdown-Text muss zunächst in HTML transformiert werden. Dies kann mit remark und rehype erreicht werden.

remark ist ein Ökosystem von Tools rund um Markdown. rehype ist das gleiche, aber für HTML. Das folgende Codebeispiel transformiert Markdown in HTML:

import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkRehype from 'remark-rehype'
import rehypeSanitize from 'rehype-sanitize'
import rehypeStringify from 'rehype-stringify'

main()

async function main() {
  const file = await unified()
    .use(remarkParse) // In Markdown-AST konvertieren
    .use(remarkRehype) // In HTML-AST transformieren
    .use(rehypeSanitize) // HTML-Eingabe bereinigen
    .use(rehypeStringify) // AST in serialisiertes HTML konvertieren
    .process('Hello, Next.js!')

  console.log(String(file)) // <p>Hello, Next.js!</p>
}

Das remark- und rehype-Ökosystem enthält Plugins für Syntax-Hervorhebung, verlinkte Überschriften, Generierung eines Inhaltsverzeichnisses und mehr.

Wenn Sie @next/mdx wie oben gezeigt verwenden, müssen Sie remark oder rehype nicht direkt verwenden, da dies für Sie übernommen wird. Wir beschreiben es hier für ein tieferes Verständnis dessen, was das @next/mdx-Paket im Hintergrund tut.

Verwendung des Rust-basierten MDX-Compilers (Experimentell)

Next.js unterstützt einen neuen MDX-Compiler, der in Rust geschrieben wurde. Dieser Compiler ist noch experimentell und wird nicht für den Produktionseinsatz empfohlen. Um den neuen Compiler zu verwenden, müssen Sie next.config.js konfigurieren, wenn Sie sie an withMDX übergeben:

next.config.js
module.exports = withMDX({
  experimental: {
    mdxRs: true,
  },
})