Menu

Markdown und MDX

Markdown ist eine leichte Auszeichnungssprache zum Formatieren von Text. Sie ermöglicht es Ihnen, mit einfacher Textsyntax zu schreiben und in strukturell gültiges HTML zu konvertieren. Es wird häufig zum Verfassen von Inhalten auf Websites und Blogs verwendet.

Sie schreiben...

Ich **liebe** die Verwendung von [Next.js](https://nextjs.org/)

Ausgabe:

<p>Ich <strong>liebe</strong> die Verwendung von <a href="https://nextjs.org/">Next.js</a></p>

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

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

Hinweis: Sehen Sie sich die Portfolio Starter Kit-Vorlage für ein vollständiges funktionierendes Beispiel an.

Abhängigkeiten installieren

Das Paket @next/mdx und verwandte Pakete werden verwendet, um Next.js so zu konfigurieren, dass es Markdown und MDX verarbeiten kann. Es bezieht Daten aus lokalen Dateien und ermöglicht Ihnen das Erstellen von Seiten mit der Erweiterung .md oder .mdx direkt in Ihrem /pages- oder /app-Verzeichnis.

Installieren Sie diese Pakete, um MDX mit Next.js zu rendern:

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

next.config.mjs konfigurieren

Aktualisieren Sie die next.config.mjs-Datei im Stammverzeichnis Ihres Projekts, um sie für die Verwendung von MDX zu konfigurieren:

next.config.mjs
import createMDX from '@next/mdx'
 
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Konfigurieren Sie `pageExtensions`, um Markdown- und MDX-Dateien einzuschließen
  pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
  // Optional können Sie weitere Next.js-Konfigurationen hinzufügen
}
 
const withMDX = createMDX({
  // Fügen Sie hier Markdown-Plugins nach Wunsch hinzu
})
 
// MDX-Konfiguration mit Next.js-Konfiguration zusammenführen
export default withMDX(nextConfig)

Dies ermöglicht es .md- und .mdx-Dateien, als Seiten, Routen oder Importe in Ihrer Anwendung zu fungieren.

mdx-components.tsx-Datei hinzufügen

Erstellen Sie eine mdx-components.tsx- (oder .js-) Datei im Stammverzeichnis Ihres Projekts, um globale MDX-Komponenten zu definieren. Zum Beispiel auf der gleichen Ebene wie pages oder app oder innerhalb von src, falls zutreffend.

mdx-components.tsx
TypeScript
import type { MDXComponents } from 'mdx/types'
 
export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    ...components,
  }
}
mdx-components.js
export function useMDXComponents(components) {
  return {
    ...components,
  }
}

Hinweis:

MDX rendern

Sie können MDX mit der dateibasierten Routing-Funktion von Next.js oder durch Importieren von MDX-Dateien in andere Seiten rendern.

Verwendung des dateibasierten Routings

Bei Verwendung des dateibasierten Routings können Sie MDX-Seiten wie jede andere Seite verwenden.

Das umfasst die Möglichkeit, Metadaten zu verwenden.

Erstellen Sie eine neue MDX-Seite im /app-Verzeichnis:

  my-project
  ├── app
  │   └── mdx-page
  │       └── page.(mdx/md)
  |── mdx-components.(tsx/js)
  └── package.json

Sie können MDX in diesen Dateien verwenden und sogar React-Komponenten direkt in Ihrer MDX-Seite importieren:

import { MyComponent } from 'my-component'
 
# Willkommen auf meiner MDX-Seite!
 
Dies ist ein **fetter** und _kursiver_ Text.
 
Dies ist eine Liste in Markdown:
 
- Eins
- Zwei
- Drei
 
Schauen Sie sich meine React-Komponente an:
 
<MyComponent />

Die Navigation zur /mdx-page-Route sollte Ihre gerenderte MDX-Seite anzeigen.

Verwendung von Importen

Erstellen Sie eine neue Seite im /app-Verzeichnis und eine MDX-Datei an einem beliebigen Ort:

  my-project
  ├── app
  │   └── mdx-page
  │       └── page.(tsx/js)
  ├── markdown
  │   └── welcome.(mdx/md)
  |── mdx-components.(tsx/js)
  └── package.json

Sie können MDX in diesen Dateien verwenden und sogar React-Komponenten direkt in Ihrer MDX-Seite importieren:

markdown/welcome.mdx
import { MyComponent } from 'my-component'
 
# Willkommen auf meiner MDX-Seite!
 
Dies ist ein **fetter** und _kursiver_ Text.
 
Dies ist eine Liste in Markdown:
 
- Eins
- Zwei
- Drei
 
Schauen Sie sich meine React-Komponente an:
 
<MyComponent />

Importieren Sie die MDX-Datei in die Seite, um den Inhalt anzuzeigen:

app/mdx-page/page.tsx
TypeScript
import Welcome from '@/markdown/welcome.mdx'
 
export default function Page() {
  return <Welcome />
}

Die Navigation zur /mdx-page-Route sollte Ihre gerenderte MDX-Seite anzeigen.

Verwendung von benutzerdefinierten Stilen und Komponenten

Markdown wird, wenn es gerendert wird, auf native HTML-Elemente abgebildet. Das Schreiben des folgenden Markdowns:

## Dies ist eine Überschrift
 
Dies ist eine Liste in Markdown:
 
- Eins
- Zwei
- Drei

Generiert das folgende HTML:

<h2>Dies ist eine Überschrift</h2>
 
<p>Dies ist eine Liste in Markdown:</p>
 
<ul>
  <li>Eins</li>
  <li>Zwei</li>
  <li>Drei</li>
</ul>

Um Ihr Markdown zu gestalten, können Sie benutzerdefinierte Komponenten bereitstellen, die den generierten HTML-Elementen zugeordnet werden. Stile und Komponenten können global, lokal und mit gemeinsamen Layouts implementiert werden.

Globale Stile und Komponenten

Das Hinzufügen von Stilen und Komponenten in mdx-components.tsx wirkt sich auf alle MDX-Dateien in Ihrer Anwendung aus.

mdx-components.tsx
TypeScript
import type { MDXComponents } from 'mdx/types'
import Image, { ImageProps } 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-Styles,
// Komponenten anderer Bibliotheken und mehr.
 
export function useMDXComponents(components: MDXComponents): MDXComponents {
  return {
    // Ermöglicht das Anpassen integrierter Komponenten, z.B. zum Hinzufügen von Styling.
    h1: ({ children }) => (
      <h1 style={{ color: 'red', fontSize: '48px' }}>{children}</h1>
    ),
    img: (props) => (
      <Image
        sizes="100vw"
        style={{ width: '100%', height: 'auto' }}
        {...(props as ImageProps)}
      />
    ),
    ...components,
  }
}
mdx-components.js
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-Styles,
// Komponenten anderer Bibliotheken und mehr.
 
export function useMDXComponents(components) {
  return {
    // Ermöglicht das Anpassen integrierter Komponenten, z.B. zum Hinzufügen von Styling.
    h1: ({ children }) => (
      <h1 style={{ color: 'red', fontSize: '48px' }}>{children}</h1>
    ),
    img: (props) => (
      <Image
        sizes="100vw"
        style={{ width: '100%', height: 'auto' }}
        {...props}
      />
    ),
    ...components,
  }
}

Lokale Stile und Komponenten

Sie können lokale Stile und Komponenten auf bestimmte Seiten anwenden, indem Sie diese in importierte MDX-Komponenten übergeben. Diese werden mit globalen Stilen und Komponenten zusammengeführt und überschreiben diese.

app/mdx-page/page.tsx
TypeScript
import Welcome from '@/markdown/welcome.mdx'
 
function CustomH1({ children }) {
  return <h1 style={{ color: 'blue', fontSize: '100px' }}>{children}</h1>
}
 
const overrideComponents = {
  h1: CustomH1,
}
 
export default function Page() {
  return <Welcome components={overrideComponents} />
}

Gemeinsame Layouts

Um ein Layout für MDX-Seiten zu teilen, können Sie die integrierte Layout-Unterstützung mit dem App Router verwenden.

app/mdx-page/layout.tsx
TypeScript
export default function MdxLayout({ children }: { children: React.ReactNode }) {
  // Erstellen Sie hier ein beliebiges gemeinsames Layout oder Stile
  return <div style={{ color: 'blue' }}>{children}</div>
}

Verwendung des Tailwind-Typografie-Plugins

Wenn Sie Tailwind zur Gestaltung Ihrer Anwendung verwenden, ermöglicht Ihnen das @tailwindcss/typography-Plugin die Wiederverwendung Ihrer Tailwind-Konfiguration und -Stile in Ihren Markdown-Dateien.

Das Plugin fügt eine Reihe von prose-Klassen hinzu, die verwendet werden können, um typografische Stile zu Inhaltsblöcken hinzuzufügen, die aus Quellen wie Markdown stammen.

Installieren Sie Tailwind-Typografie und verwenden Sie es mit gemeinsamen Layouts, um das gewünschte prose hinzuzufügen.

app/mdx-page/layout.tsx
TypeScript
export default function MdxLayout({ children }: { children: React.ReactNode }) {
  // Erstellen Sie hier ein beliebiges gemeinsames Layout oder Stile
  return (
    <div className="prose prose-headings:mt-8 prose-headings:font-semibold prose-headings:text-black prose-h1:text-5xl prose-h2:text-4xl prose-h3:text-3xl prose-h4:text-2xl prose-h5:text-xl prose-h6:text-lg dark:prose-headings:text-white">
      {children}
    </div>
  )
}

Frontmatter

Frontmatter ist eine YAML-ähnliche Schlüssel/Wert-Zuordnung, die verwendet werden kann, um Daten über eine Seite zu speichern. @next/mdx unterstützt Frontmatter nicht standardmäßig, es gibt jedoch viele Lösungen zum Hinzufügen von Frontmatter zu Ihrem MDX-Inhalt, wie:

@next/mdx erlaubt es Ihnen, Exporte wie jede andere JavaScript-Komponente zu verwenden:

content/blog-post.mdx
export const metadata = {
  author: 'John Doe',
}
 
# Blog-Beitrag

Metadaten können jetzt außerhalb der MDX-Datei referenziert werden:

app/blog/page.tsx
TypeScript
import BlogPost, { metadata } from '@/content/blog-post.mdx'
 
export default function Page() {
  console.log('metadata: ', metadata)
  //=> { author: 'John Doe' }
  return <BlogPost />
}

Ein häufiger Anwendungsfall hierfür ist, wenn Sie eine Sammlung von MDX durchlaufen und Daten extrahieren möchten. Zum Beispiel beim Erstellen einer Blog-Indexseite aus allen Blog-Beiträgen. Sie können Pakete wie Node's fs-Modul oder globby verwenden, um ein Verzeichnis von Beiträgen zu lesen und die Metadaten zu extrahieren.

Hinweis:

  • Die Verwendung von fs, globby usw. kann nur serverseitig erfolgen.
  • Sehen Sie sich die Portfolio-Starter-Kit Vorlage für ein vollständiges funktionierendes Beispiel an.

Remark- und Rehype-Plugins

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

Zum Beispiel 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', 'md', 'mdx', 'ts', 'tsx'],
  // Optional können Sie weitere Next.js-Konfigurationen hinzufügen
}
 
const withMDX = createMDX({
  // Fügen Sie hier Markdown-Plugins nach Wunsch hinzu
  options: {
    remarkPlugins: [remarkGfm],
    rehypePlugins: [],
  },
})
 
// MDX- und Next.js-Konfiguration miteinander umschließen
export default withMDX(nextConfig)

Entferntes MDX

Wenn sich Ihre MDX-Dateien oder -Inhalte woanders befinden, können Sie sie dynamisch auf dem Server abrufen. Dies ist nützlich für Inhalte, die in einem separaten lokalen Ordner, CMS, Datenbank oder anderswo gespeichert sind. Ein beliebtes Community-Paket für diesen Zweck ist next-mdx-remote.

Hinweis: Gehen Sie mit Vorsicht vor. MDX wird zu JavaScript kompiliert und auf dem Server ausgeführt. Sie sollten MDX-Inhalte nur aus einer vertrauenswürdigen Quelle abrufen, da es sonst zu Remote-Code-Ausführung (RCE) führen kann.

Das folgende Beispiel verwendet next-mdx-remote:

app/mdx-page-remote/page.tsx
TypeScript
import { MDXRemote } from 'next-mdx-remote/rsc'
 
export default async function RemoteMdxPage() {
  // MDX-Text - kann aus einer lokalen Datei, Datenbank, CMS, Fetch usw. stammen...
  const res = await fetch('https://...')
  const markdown = await res.text()
  return <MDXRemote source={markdown} />
}

Der Aufruf der /mdx-page-remote-Route sollte Ihr gerendertes MDX anzeigen.

Vertiefung: Wie transformiert man Markdown in HTML?

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

remark ist ein Ökosystem von Tools rund um Markdown. rehype ist dasselbe, aber für HTML. Zum Beispiel transformiert der folgende Code-Snippet 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 umwandeln
    .use(remarkRehype) // In HTML-AST transformieren
    .use(rehypeSanitize) // HTML-Eingabe bereinigen
    .use(rehypeStringify) // AST in serialisiertes HTML umwandeln
    .process('Hallo, Next.js!')
 
  console.log(String(file)) // <p>Hallo, Next.js!</p>
}

Das remark- und rehype-Ökosystem enthält Plugins für Syntaxhervorhebung, Überschriften verlinken, Inhaltsverzeichnis generieren und mehr.

Bei Verwendung von @next/mdx wie oben gezeigt, müssen Sie remark oder rehype nicht direkt verwenden, da dies für Sie erledigt wird. Wir beschreiben es hier für ein tieferes Verständnis dessen, was das @next/mdx-Paket unter der Haube macht.

Verwendung des Rust-basierten MDX-Compilers (experimentell)

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

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

mdxRs akzeptiert auch ein Objekt zur Konfiguration der MDX-Dateitransformation.

next.config.js
module.exports = withMDX({
  experimental: {
    mdxRs: {
      jsxRuntime?: string            // Benutzerdefinierte jsx-Laufzeit
      jsxImportSource?: string       // Benutzerdefinierte jsx-Import-Quelle,
      mdxType?: 'gfm' | 'commonmark' // Konfigurieren Sie, welche MDX-Syntax zum Parsen und Transformieren verwendet wird
    },
  },
})

Hinweis:

Diese Option ist erforderlich, wenn Markdown und MDX bei Verwendung von Turbopack (next dev --turbopack) verarbeitet werden.