Statische Exporte

Next.js ermöglicht den Start als statische Website oder Single-Page Application (SPA), mit der Option später Server-Features hinzuzufügen.

Bei Ausführung von next build generiert Next.js eine HTML-Datei pro Route. Durch die Aufteilung einer strikten SPA in einzelne HTML-Dateien kann Next.js unnötigen JavaScript-Code auf Client-Seite vermeiden, was die Bundle-Größe reduziert und schnellere Ladezeiten ermöglicht.

Da Next.js diesen statischen Export unterstützt, kann es auf jedem Webserver bereitgestellt werden, der statische HTML/CSS/JS-Assets servieren kann.

Konfiguration

Um einen statischen Export zu aktivieren, ändern Sie den Ausgabemodus in next.config.js:

next.config.js
/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
  output: 'export',

  // Optional: Ändert Links `/me` -> `/me/` und erzeugt `/me.html` -> `/me/index.html`
  // trailingSlash: true,

  // Optional: Verhindert automatische Umleitung `/me` -> `/me/`, behält `href` bei
  // skipTrailingSlashRedirect: true,

  // Optional: Ändert das Ausgabeverzeichnis `out` -> `dist`
  // distDir: 'dist',
}

module.exports = nextConfig

Nach Ausführung von next build erstellt Next.js einen out-Ordner mit den HTML/CSS/JS-Assets Ihrer Anwendung.

Unterstützte Features

Der Kern von Next.js wurde für statische Exporte konzipiert.

Server Components

Bei Ausführung von next build für einen statischen Export werden Server Components im app-Verzeichnis während des Builds ausgeführt, ähnlich wie bei traditioneller Static-Site-Generierung.

Die resultierende Komponente wird als statisches HTML für den initialen Seitenaufruf gerendert und als statische Payload für Client-seitige Navigation zwischen Routen. Für Server Components sind bei Verwendung des statischen Exports keine Änderungen erforderlich, es sei denn, sie verwenden dynamische Server-Funktionen.

export default async function Page() {
  // Dieser Fetch läuft auf dem Server während `next build`
  const res = await fetch('https://api.example.com/...')
  const data = await res.json()

  return <main>...</main>
}

Client Components

Für Client-seitiges Data Fetching können Sie eine Client Component mit SWR verwenden, um Anfragen zwischenzuspeichern.

'use client'

import useSWR from 'swr'

const fetcher = (url: string) => fetch(url).then((r) => r.json())

export default function Page() {
  const { data, error } = useSWR(
    `https://jsonplaceholder.typicode.com/posts/1`,
    fetcher
  )
  if (error) return 'Fehler beim Laden'
  if (!data) return 'Lädt...'

  return data.title
}
'use client'

import useSWR from 'swr'

const fetcher = (url) => fetch(url).then((r) => r.json())

export default function Page() {
  const { data, error } = useSWR(
    `https://jsonplaceholder.typicode.com/posts/1`,
    fetcher
  )
  if (error) return 'Fehler beim Laden'
  if (!data) return 'Lädt...'

  return data.title
}

Da Routenübergänge client-seitig erfolgen, verhält sich dies wie eine traditionelle SPA. Beispielsweise ermöglicht die folgende Index-Route die Navigation zu verschiedenen Beiträgen auf Client-Seite:

import Link from 'next/link'

export default function Page() {
  return (
    <>
      <h1>Index-Seite</h1>
      <hr />
      <ul>
        <li>
          <Link href="/post/1">Beitrag 1</Link>
        </li>
        <li>
          <Link href="/post/2">Beitrag 2</Link>
        </li>
      </ul>
    </>
  )
}
import Link from 'next/link'

export default function Page() {
  return (
    <>
      <h1>Index-Seite</h1>
      <p>
        <Link href="/other">Andere Seite</Link>
      </p>
    </>
  )
}

Bildoptimierung

Bildoptimierung via next/image kann mit einem statischen Export verwendet werden, indem ein benutzerdefinierter Image Loader in next.config.js definiert wird. Beispielsweise können Bilder mit einem Dienst wie Cloudinary optimiert werden:

next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export',
  images: {
    loader: 'custom',
    loaderFile: './my-loader.ts',
  },
}

module.exports = nextConfig

Dieser benutzerdefinierte Loader definiert, wie Bilder von einer Remote-Quelle abgerufen werden. Beispielsweise konstruiert der folgende Loader die URL für Cloudinary:

export default function cloudinaryLoader({
  src,
  width,
  quality,
}: {
  src: string
  width: number
  quality?: number
}) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(
    ','
  )}${src}`
}
export default function cloudinaryLoader({ src, width, quality }) {
  const params = ['f_auto', 'c_limit', `w_${width}`, `q_${quality || 'auto'}`]
  return `https://res.cloudinary.com/demo/image/upload/${params.join(
    ','
  )}${src}`
}

Sie können dann next/image in Ihrer Anwendung verwenden und relative Pfade zu den Bildern in Cloudinary angeben:

import Image from 'next/image'

export default function Page() {
  return <Image alt="turtles" src="/turtles.jpg" width={300} height={300} />
}
import Image from 'next/image'

export default function Page() {
  return <Image alt="turtles" src="/turtles.jpg" width={300} height={300} />
}

Route Handlers

Route Handlers rendern eine statische Antwort bei Ausführung von next build. Nur das GET HTTP-Verb wird unterstützt. Dies kann verwendet werden, um statische HTML-, JSON-, TXT- oder andere Dateien aus gecachten oder ungecachten Daten zu generieren. Beispiel:

export async function GET() {
  return Response.json({ name: 'Lee' })
}
export async function GET() {
  return Response.json({ name: 'Lee' })
}

Die obige Datei app/data.json/route.ts wird während next build in eine statische Datei gerendert und erzeugt data.json mit dem Inhalt { name: 'Lee' }.

Wenn Sie dynamische Werte aus der eingehenden Anfrage lesen müssen, können Sie keinen statischen Export verwenden.

Browser APIs

Client Components werden während next build zu HTML vorgerendert. Da Web APIs wie window, localStorage und navigator auf dem Server nicht verfügbar sind, müssen Sie sicherstellen, dass diese APIs nur im Browser aufgerufen werden. Beispiel:

'use client';

import { useEffect } from 'react';

export default function ClientComponent() {
  useEffect(() => {
    // Jetzt haben Sie Zugriff auf `window`
    console.log(window.innerHeight);
  }, [])

  return ...;
}

Nicht unterstützte Features

Features, die einen Node.js-Server erfordern oder dynamische Logik, die nicht während des Build-Prozesses berechnet werden kann, werden nicht unterstützt:

Der Versuch, diese Features mit next dev zu verwenden, führt zu einem Fehler, ähnlich wie das Setzen der dynamic-Option auf error im Root-Layout.

export const dynamic = 'error'

Bereitstellung

Mit einem statischen Export kann Next.js auf jedem Webserver bereitgestellt werden, der statische HTML/CSS/JS-Assets servieren kann.

Bei Ausführung von next build generiert Next.js den statischen Export in den out-Ordner. Angenommen, Sie haben folgende Routen:

  • /
  • /blog/[id]

Nach next build erzeugt Next.js folgende Dateien:

  • /out/index.html
  • /out/404.html
  • /out/blog/post-1.html
  • /out/blog/post-2.html

Bei Verwendung eines statischen Hosts wie Nginx können Sie Rewrites von eingehenden Anfragen zu den korrekten Dateien konfigurieren:

nginx.conf
server {
  listen 80;
  server_name acme.com;

  root /var/www/out;

  location / {
      try_files $uri $uri.html $uri/ =404;
  }

  # Dies ist notwendig bei `trailingSlash: false`.
  # Kann weggelassen werden bei `trailingSlash: true`.
  location /blog/ {
      rewrite ^/blog/(.*)$ /blog/$1.html break;
  }

  error_page 404 /404.html;
  location = /404.html {
      internal;
  }
}

Versionsverlauf

VersionÄnderungen
v14.0.0next export wurde zugunsten von "output": "export" entfernt
v13.4.0App Router (Stable) fügt erweiterte Unterstützung für statische Exporte hinzu, inklusive React Server Components und Route Handlers.
v13.3.0next export ist veraltet und wird durch "output": "export" ersetzt