Selbsthosting Ihrer Next.js-Anwendung
Wenn Sie Ihre Next.js-App bereitstellen, möchten Sie möglicherweise konfigurieren, wie verschiedene Funktionen basierend auf Ihrer Infrastruktur behandelt werden.
🎥 Video ansehen: Mehr über das Selbsthosting von Next.js erfahren → YouTube (45 Minuten).
Bildoptimierung
Die Bildoptimierung über next/image
funktioniert beim Selbsthosting ohne zusätzliche Konfiguration, wenn Sie next start
verwenden. Wenn Sie lieber einen separaten Dienst zur Bildoptimierung nutzen möchten, können Sie einen Image Loader konfigurieren.
Die Bildoptimierung kann mit einem statischen Export verwendet werden, indem Sie einen benutzerdefinierten Image Loader in next.config.js
definieren. Beachten Sie, dass Bilder zur Laufzeit und nicht während des Builds optimiert werden.
Wissenswert:
- Auf glibc-basierten Linux-Systemen kann die Bildoptimierung eine zusätzliche Konfiguration erfordern, um übermäßigen Speicherverbrauch zu verhindern.
- Erfahren Sie mehr über das Caching-Verhalten optimierter Bilder und wie Sie die TTL konfigurieren können.
- Sie können die Bildoptimierung auch deaktivieren und dennoch die anderen Vorteile von
next/image
nutzen, wenn Sie dies bevorzugen. Zum Beispiel, wenn Sie Bilder separat selbst optimieren.
Middleware
Middleware funktioniert beim Selbsthosting ohne zusätzliche Konfiguration, wenn Sie next start
verwenden. Da sie Zugriff auf die eingehende Anfrage benötigt, wird sie nicht unterstützt, wenn Sie einen statischen Export verwenden.
Middleware nutzt die Edge Runtime, eine Teilmenge aller verfügbaren Node.js-APIs, um eine geringe Latenz zu gewährleisten, da sie vor jeder Route oder jedem Asset Ihrer Anwendung ausgeführt werden kann. Wenn Sie dies nicht möchten, können Sie die vollständige Node.js-Runtime für die Middleware verwenden.
Wenn Sie Logik hinzufügen möchten (oder ein externes Paket verwenden), das alle Node.js-APIs benötigt, können Sie diese Logik möglicherweise in ein Layout als Server-Komponente verschieben. Zum Beispiel das Überprüfen von Headers und Weiterleitungen. Sie können auch Header, Cookies oder Abfrageparameter verwenden, um über next.config.js
Weiterleitungen oder Rewrites durchzuführen. Falls das nicht funktioniert, können Sie auch einen benutzerdefinierten Server verwenden.
Umgebungsvariablen
Next.js unterstützt sowohl Build-Zeit- als auch Laufzeit-Umgebungsvariablen.
Standardmäßig sind Umgebungsvariablen nur auf dem Server verfügbar. Um eine Umgebungsvariable im Browser verfügbar zu machen, muss sie mit NEXT_PUBLIC_
prefixiert werden. Diese öffentlichen Umgebungsvariablen werden jedoch während next build
in das JavaScript-Bundle eingebettet.
Sie können Umgebungsvariablen sicher auf dem Server während des dynamischen Renderings lesen.
import { connection } from 'next/server'
export default async function Component() {
await connection()
// cookies, headers und andere Dynamic APIs
// werden auch dynamisches Rendering auslösen, was bedeutet,
// dass diese Umgebungsvariable zur Laufzeit ausgewertet wird
const value = process.env.MY_VALUE
// ...
}
import { connection } from 'next/server'
export default async function Component() {
await connection()
// cookies, headers und andere Dynamic APIs
// werden auch dynamisches Rendering auslösen, was bedeutet,
// dass diese Umgebungsvariable zur Laufzeit ausgewertet wird
const value = process.env.MY_VALUE
// ...
}
Dies ermöglicht es Ihnen, ein einziges Docker-Image zu verwenden, das in mehreren Umgebungen mit unterschiedlichen Werten bereitgestellt werden kann.
Wissenswert:
- Sie können Code beim Serverstart mit der
register
-Funktion ausführen.- Wir empfehlen nicht die Verwendung der runtimeConfig-Option, da diese nicht mit dem standalone-Output-Modus funktioniert. Stattdessen empfehlen wir die schrittweise Migration zum App Router.
Caching und ISR
Next.js kann Antworten, generierte statische Seiten, Build-Outputs und andere statische Assets wie Bilder, Schriftarten und Skripte cachen.
Caching und Revalidierung von Seiten (mit Inkrementellem Statischen Regenerieren (ISR)) nutzen den gleichen gemeinsamen Cache. Standardmäßig wird dieser Cache im Dateisystem (auf der Festplatte) Ihres Next.js-Servers gespeichert. Dies funktioniert automatisch beim Selbsthosting sowohl mit dem Pages- als auch mit dem App-Router.
Sie können den Next.js-Cache-Speicherort konfigurieren, wenn Sie zwischengespeicherte Seiten und Daten in dauerhaften Speicher persistieren oder den Cache über mehrere Container oder Instanzen Ihrer Next.js-Anwendung teilen möchten.
Automatisches Caching
- Next.js setzt den
Cache-Control
-Header vonpublic, max-age=31536000, immutable
für wirklich unveränderliche Assets. Dies kann nicht überschrieben werden. Diese unveränderlichen Dateien enthalten einen SHA-Hash im Dateinamen und können daher sicher unbegrenzt zwischengespeichert werden. Zum Beispiel Statische Bildimporte. Sie können die TTL für Bilder konfigurieren. - Inkrementelles Statisches Regenerieren (ISR) setzt den
Cache-Control
-Header aufs-maxage: <revalidate in getStaticProps>, stale-while-revalidate
. Diese Revalidierungszeit wird in IhrergetStaticProps
-Funktion in Sekunden definiert. Wenn Sierevalidate: false
setzen, wird standardmäßig eine Cache-Dauer von einem Jahr verwendet. - Dynamisch gerenderte Seiten setzen einen
Cache-Control
-Header vonprivate, no-cache, no-store, max-age=0, must-revalidate
, um das Caching benutzerspezifischer Daten zu verhindern. Dies gilt sowohl für den App- als auch für den Pages-Router. Dazu gehört auch der Draft Mode.
Statische Assets
Wenn Sie statische Assets auf einer anderen Domain oder einem CDN hosten möchten, können Sie die assetPrefix
-Konfiguration in next.config.js
verwenden. Next.js verwendet dieses Asset-Präfix beim Abrufen von JavaScript- oder CSS-Dateien. Die Trennung Ihrer Assets auf eine andere Domain hat jedoch den Nachteil einer zusätzlichen Zeit für DNS- und TLS-Auflösung.
Mehr über assetPrefix
erfahren.
Caching konfigurieren
Standardmäßig werden zwischengespeicherte Assets im Speicher (standardmäßig 50 MB) und auf der Festplatte gespeichert. Wenn Sie Next.js mit einer Container-Orchestrierungsplattform wie Kubernetes hosten, hat jeder Pod eine Kopie des Caches. Um zu verhindern, dass veraltete Daten angezeigt werden, da der Cache standardmäßig nicht zwischen Pods geteilt wird, können Sie den Next.js-Cache so konfigurieren, dass er einen Cache-Handler bereitstellt und das In-Memory-Caching deaktiviert.
Um den ISR/Daten-Cache-Speicherort beim Selbsthosting zu konfigurieren, können Sie einen benutzerdefinierten Handler in Ihrer next.config.js
-Datei konfigurieren:
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
cacheMaxMemorySize: 0, // Standard-In-Memory-Caching deaktivieren
}
Erstellen Sie dann cache-handler.js
im Stammverzeichnis Ihres Projekts, zum Beispiel:
const cache = new Map()
module.exports = class CacheHandler {
constructor(options) {
this.options = options
}
async get(key) {
// Dies könnte überall gespeichert werden, wie in dauerhaftem Speicher
return cache.get(key)
}
async set(key, data, ctx) {
// Dies könnte überall gespeichert werden, wie in dauerhaftem Speicher
cache.set(key, {
value: data,
lastModified: Date.now(),
tags: ctx.tags,
})
}
async revalidateTag(tags) {
// tags ist entweder ein String oder ein Array von Strings
tags = [tags].flat()
// Durch alle Einträge im Cache iterieren
for (let [key, value] of cache) {
// Wenn die Tags des Wertes den angegebenen Tag enthalten, diesen Eintrag löschen
if (value.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
}
// Wenn Sie einen temporären In-Memory-Cache für eine einzelne Anfrage haben möchten, der zurückgesetzt wird
// bevor die nächste Anfrage kommt, können Sie diese Methode nutzen
resetRequestCache() {}
}
Die Verwendung eines benutzerdefinierten Cache-Handlers ermöglicht es Ihnen, Konsistenz über alle Pods hinweg sicherzustellen, die Ihre Next.js-Anwendung hosten. Sie können die zwischengespeicherten Werte beispielsweise überall speichern, wie in Redis oder AWS S3.
Wissenswert:
revalidatePath
ist eine bequeme Abstraktion über Cache-Tags. Der Aufruf vonrevalidatePath
ruft dierevalidateTag
-Funktion mit einem speziellen Standard-Tag für die angegebene Seite auf.
Build-Cache
Next.js generiert während next build
eine ID, um zu identifizieren, welche Version Ihrer Anwendung bereitgestellt wird. Der gleiche Build sollte verwendet und auf mehreren Containern gestartet werden.
Wenn Sie für jede Stufe Ihrer Umgebung neu bauen, müssen Sie eine konsistente Build-ID generieren, die zwischen Containern verwendet wird. Verwenden Sie den generateBuildId
-Befehl in next.config.js
:
module.exports = {
generateBuildId: async () => {
// Dies könnte alles sein, z.B. der neueste Git-Hash
return process.env.GIT_HASH
},
}
Version Skew
Next.js mildert die meisten Fälle von Version Skew automatisch und lädt die Anwendung automatisch neu, um neue Assets abzurufen, wenn eine Abweichung erkannt wird. Wenn beispielsweise eine Diskrepanz in der deploymentId
besteht, führen Übergänge zwischen Seiten eine Hard Navigation durch, anstatt einen vorab abgerufenen Wert zu verwenden.
Wenn die Anwendung neu geladen wird, kann der Anwendungszustand verloren gehen, wenn er nicht dafür ausgelegt ist, zwischen Seitenübergängen zu bestehen. Zum Beispiel würde die Verwendung von URL-State oder Local Storage den Zustand nach einem Seitenneuladen erhalten. Komponentenstatus wie useState
würde jedoch bei solchen Navigationen verloren gehen.
Streaming und Suspense
Der Next.js App Router unterstützt Streaming-Antworten beim Selbsthosting. Wenn Sie Nginx oder einen ähnlichen Proxy verwenden, müssen Sie diesen so konfigurieren, dass das Buffering deaktiviert wird, um Streaming zu ermöglichen.
Zum Beispiel können Sie das Buffering in Nginx deaktivieren, indem Sie X-Accel-Buffering
auf no
setzen:
module.exports = {
async headers() {
return [
{
source: '/:path*{/}?',
headers: [
{
key: 'X-Accel-Buffering',
value: 'no',
},
],
},
]
},
}
Partielles Prerendering
Partielles Prerendering (experimentell) funktioniert standardmäßig mit Next.js und ist keine CDN-exklusive Funktion. Dies gilt für die Bereitstellung als Node.js-Server (über next start
) und bei Verwendung mit einem Docker-Container.
Verwendung mit CDNs
Wenn Sie ein CDN vor Ihrer Next.js-Anwendung verwenden, enthält die Seite den Cache-Control: private
-Response-Header, wenn auf dynamische APIs zugegriffen wird. Dadurch wird sichergestellt, dass die resultierende HTML-Seite als nicht-cachebar markiert wird. Wenn die Seite vollständig statisch prerendert wurde, enthält sie Cache-Control: public
, um das Caching der Seite auf dem CDN zu ermöglichen.
Wenn Sie keine Mischung aus statischen und dynamischen Komponenten benötigen, können Sie Ihre gesamte Route statisch machen und den HTML-Output auf einem CDN cachen. Diese automatische statische Optimierung ist das Standardverhalten bei der Ausführung von next build
, wenn keine dynamischen APIs verwendet werden.
Wenn Partielles Prerendering stabil wird, werden wir Unterstützung über die Deployment Adapters API bereitstellen.
after
after
wird vollständig unterstützt, wenn Sie mit next start
selbst hosten.
Beim Stoppen des Servers sollten Sie einen ordnungsgemäßen Shutdown durchführen, indem Sie SIGINT
oder SIGTERM
-Signale senden und warten. Dadurch kann der Next.js-Server warten, bis ausstehende Callback-Funktionen oder Promises innerhalb von after
abgeschlossen sind.