Wie bekomme ich die aktuelle Seiten-URL in Gatsby

Avatar of Dmitry Mayorov
Dmitry Mayorov am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Diese scheinbar einfache Aufgabe hat mich ein paar Stunden lang am Kopf kratzen lassen, während ich an meiner Website gearbeitet habe. Wie sich herausstellt, ist das Abrufen der aktuellen Seiten-URL in Gatsby nicht so einfach, wie Sie vielleicht denken, aber auch nicht so kompliziert zu verstehen.

Schauen wir uns ein paar Methoden an, wie das gelingt. Aber zuerst fragen Sie sich vielleicht, warum wir so etwas überhaupt tun sollten.

Warum Sie die aktuelle URL benötigen könnten

Bevor wir zum *Wie* kommen, beantworten wir zuerst die größere Frage: Warum sollten Sie die URL der aktuellen Seite abrufen wollen? Ich kann ein paar Anwendungsfälle anbieten.

Meta-Tags

Das erste offensichtliche Bedürfnis nach der aktuellen URL sind Meta-Tags im Kopfbereich des Dokuments.

<link rel="canonical" href={url} />
<meta property="og:url" content={url} />

Social Sharing

Ich habe es auf mehreren Websites gesehen, wo ein Link zur aktuellen Seite neben den Sharing-Buttons angezeigt wird. So etwas wie hier (gefunden auf Creative Market)

Styling

Das ist weniger offensichtlich, aber ich habe es schon ein paar Mal mit styled-components verwendet. Sie können verschiedene Stile basierend auf bestimmten Bedingungen rendern. Eine dieser Bedingungen kann ein Seitenpfad sein (d. h. ein Teil der URL nach dem Namen der Website). Hier ist ein kurzes Beispiel

import React from 'react';
import styled from 'styled-components';

const Layout = ({ path, children }) => (
  <StyledLayout path={path}>
    {children}
  </StyledLayout>
);
    
const StyledLayout = styled.main`
  background-color: ${({ path }) => (path === '/' ? '#fff' : '#000')};
`;

export default Layout;

Hier habe ich eine gestylte Layout-Komponente erstellt, die basierend auf dem Pfad eine andere Hintergrundfarbe hat.

Diese Liste von Beispielen veranschaulicht nur die Idee und ist keineswegs erschöpfend. Ich bin sicher, dass es noch weitere Fälle gibt, in denen Sie die URL der aktuellen Seite abrufen möchten. Wie machen wir das also?

Build-Zeit vs. Laufzeit verstehen

Nicht so schnell! Bevor wir zu den eigentlichen Methoden und Code-Snippets kommen, möchte ich noch einen letzten Stopp einlegen und kurz einige Kernkonzepte von Gatsby erklären.

Das Erste, was wir verstehen müssen, ist, dass Gatsby unter anderem ein Static Site Generator ist. Das bedeutet, dass es statische Dateien (normalerweise HTML und JavaScript) erstellt. Auf der Produktionswebsite gibt es keinen Server und keine Datenbank. Alle Informationen (einschließlich der aktuellen Seiten-URL) müssen aus anderen Quellen bezogen oder während der Build-Zeit oder Laufzeit generiert werden, bevor sie in das Markup eingefügt werden.

Das bringt uns zum zweiten wichtigen Konzept, das wir verstehen müssen: Build-Zeit vs. Laufzeit. Ich ermutige Sie, die offizielle Gatsby-Dokumentation dazu zu lesen, aber hier ist meine Interpretation.

Laufzeit ist, wenn eine der statischen Seiten im Browser geöffnet wird. In diesem Fall hat die Seite Zugriff auf alle wunderbaren Browser-APIs, einschließlich der Window API, die unter anderem die aktuelle Seiten-URL enthält.

Eine Sache, die man leicht verwechseln kann, besonders wenn man mit Gatsby anfängt, ist, dass das Ausführen von gatsby develop im Terminal im Entwicklungsmodus den Browser für Sie startet. Das bedeutet, dass alle Referenzen auf das Window-Objekt funktionieren und keine Fehler auslösen.

Build-Zeit findet statt, wenn Sie mit der Entwicklung fertig sind und Gatsby anweisen, endgültige optimierte Assets mit dem Befehl gatsby build zu generieren. Während der Build-Zeit existiert der Browser nicht. Das bedeutet, dass Sie das Window-Objekt nicht verwenden können.

Hier kommt der *Aha!*-Moment. Wenn Builds vom Browser isoliert sind und es keinen Server oder keine Datenbank gibt, von wo wir die URL beziehen könnten, woher soll Gatsby dann wissen, welche Domain verwendet wird? Das ist die Sache – das kann es nicht! Sie können den Slug oder Pfad der Seite abrufen, aber Sie können einfach nicht sagen, was die Basis-URL ist. Sie müssen sie angeben.

Das ist ein sehr grundlegendes Konzept, aber wenn Sie neu sind und jahrelange WordPress-Erfahrung haben, kann es eine Weile dauern, bis diese Information sackt. Sie wissen, dass Gatsby serverlos ist und alles, aber Momente wie dieser lassen Sie erkennen: Es gibt keinen Server.

Nachdem wir das geklärt haben, springen wir zu den eigentlichen Methoden, um die URL der aktuellen Seite abzurufen.

Methode 1: Verwenden Sie die href-Eigenschaft des window.location-Objekts

Diese erste Methode ist nicht spezifisch für Gatsby und kann in praktisch jeder JavaScript-Anwendung im Browser verwendet werden. Sehen Sie, *Browser* ist hier das Schlüsselwort.

Nehmen wir an, Sie bauen eine dieser Sharing-Komponenten mit einem Eingabefeld, das die URL der aktuellen Seite enthalten muss. Hier ist, wie Sie das tun könnten

import React from 'react';

const Foo = () => {
  const url = typeof window !== 'undefined' ? window.location.href : '';

  return (
    <input type="text" readOnly="readonly" value={url} />
  );
};

export default Foo;

Wenn das window-Objekt existiert, erhalten wir die href-Eigenschaft des location-Objekts, das ein Kind von window ist. Wenn nicht, geben wir der url-Variable einen leeren String-Wert.

Wenn wir es ohne die Prüfung tun und es so schreiben

const url = window.location.href;

…wird der Build mit einem Fehler fehlschlagen, der ungefähr so aussieht

failed Building static HTML for pages - 2.431s
ERROR #95312 
"window" is not available during server-side rendering.

Wie ich bereits erwähnt habe, geschieht dies, weil der Browser während der Build-Zeit nicht existiert. Das ist ein großer Nachteil dieser Methode. Sie können sie nicht verwenden, wenn die URL in der statischen Version der Seite vorhanden sein muss.

Aber es gibt auch einen großen Vorteil! Sie können auf das Window-Objekt von einer Komponente zugreifen, die tief in anderen Komponenten verschachtelt ist. Mit anderen Worten, Sie müssen die URL-Prop nicht von übergeordneten Komponenten weitergeben.

Methode 2: Holen Sie sich die href-Eigenschaft von Location-Daten aus Props

Jede Seiten- und Vorlagenkomponente in Gatsby hat eine location-Prop, die Informationen über die aktuelle Seite enthält. Im Gegensatz zu window.location ist diese Prop jedoch auf allen Seiten vorhanden.

Zitat aus den Gatsby-Dokumenten

Das Tolle ist, dass Sie die Location-Prop auf jeder Seite zur Verfügung haben.

Aber es kann hier einen Haken geben. Wenn Sie neu bei Gatsby sind, werden Sie diese Prop in die Konsole protokollieren und feststellen, dass sie window.location sehr ähnlich aussieht (aber nicht dasselbe ist) und auch das href-Attribut enthält. Wie ist das möglich? Nun, das ist es nicht. Die href-Prop ist nur zur Laufzeit vorhanden.

Das Schlimmste daran ist, dass die direkte Verwendung von location.href ohne vorherige Prüfung, ob sie existiert, während der Build-Zeit keinen Fehler auslöst.

All dies bedeutet, dass wir uns auf die location-Prop verlassen können, dass sie auf jeder Seite vorhanden ist, aber wir können nicht davon ausgehen, dass sie zur Build-Zeit die href-Eigenschaft hat. Seien Sie sich dessen bewusst und verwenden Sie diese Methode nicht für kritische Fälle, in denen Sie die URL im Markup der statischen Version der Seite benötigen.

Lassen Sie uns also das vorherige Beispiel mit dieser Methode neu schreiben

import React from 'react';

const Page = ({ location }) => {
  const url = location.href ? location.href : '';

  return (
    <input type="text" readOnly="readonly" value={url} />
  );
};

export default Page;

Dies muss eine Seiten- oder Vorlagenkomponente auf oberster Ebene sein. Sie können sie nicht einfach irgendwo importieren und erwarten, dass sie funktioniert. Die location-Prop wird undefiniert sein.

Wie Sie sehen, ist diese Methode ziemlich ähnlich zur vorherigen. Verwenden Sie sie für Fälle, in denen die URL nur zur Laufzeit benötigt wird.

Aber was, wenn Sie eine vollständige URL im Markup einer statischen Seite benötigen? Gehen wir zur dritten Methode über.

Methode 3: Generieren Sie die aktuelle Seiten-URL mit der pathname-Eigenschaft von Location-Daten

Wie wir zu Beginn dieses Beitrags besprochen haben, müssen Sie die Basis-URL für die Website irgendwo angeben und sie zur Build-Zeit abrufen, wenn Sie die vollständige URL in die statischen Seiten einfügen möchten. Ich zeige Ihnen, wie das geht.

Als Beispiel erstelle ich einen <link rel="canonical" href={url} />-Tag im Header. Es ist wichtig, die vollständige Seiten-URL darin zu haben, bevor die Seite den Browser erreicht. Andernfalls sehen Suchmaschinen und Site-Scraper das leere href-Attribut, was inakzeptabel ist.

Hier ist der Plan

  1. Fügen Sie die Eigenschaft siteURL zu siteMetadata in gatsby-config.js hinzu.
  2. Erstellen Sie einen Static Query Hook, um siteMetadata in jeder Komponente abzurufen.
  3. Verwenden Sie diesen Hook, um siteURL abzurufen.
  4. Kombinieren Sie ihn mit dem Pfad der Seite und fügen Sie ihn in das Markup ein.

Lassen Sie uns jeden Schritt aufschlüsseln.

Fügen Sie die siteURL-Eigenschaft zu siteMetadata in gatsby-config.js hinzu

Gatsby hat eine Konfigurationsdatei namens gatsby-config.js, die verwendet werden kann, um globale Informationen über die Website im siteMetadata-Objekt zu speichern. Das funktioniert für uns, also fügen wir siteURL zu diesem Objekt hinzu

module.exports = {
  siteMetadata: {
    title: 'Dmitry Mayorov',
    description: 'Dmitry is a front-end developer who builds cool sites.',
    author: '@dmtrmrv',
    siteURL: 'https://dmtrmrv.com',
  }
};

Erstellen Sie einen Static Query Hook, um siteMetadata in jeder Komponente abzurufen

Als Nächstes benötigen wir eine Möglichkeit, siteMetadata in unseren Komponenten zu verwenden. Glücklicherweise hat Gatsby eine StaticQuery API, die uns genau das ermöglicht. Sie können den Hook useStaticQuery direkt in Ihren Komponenten verwenden, aber ich ziehe es vor, für jede statische Abfrage, die ich auf der Website verwende, eine separate Datei zu erstellen. Das macht den Code leichter lesbar.

Erstellen Sie dazu eine Datei namens use-site-metadata.js in einem hooks-Ordner innerhalb des src-Ordners Ihrer Website und kopieren Sie den folgenden Code hinein.

import { useStaticQuery, graphql } from 'gatsby';

const useSiteMetadata = () => {
  const { site } = useStaticQuery(
  graphql`
    query {
    site {
      siteMetadata {
      title
      description
      author
      siteURL
      }
    }
    }
  `,
  );
  return site.siteMetadata;
};

export default useSiteMetadata;

Stellen Sie sicher, dass alle Eigenschaften – wie title, description, author und alle anderen Eigenschaften, die Sie im siteMetadata-Objekt haben – in der GraphQL-Abfrage erscheinen.

Verwenden Sie diesen Hook, um siteURL abzurufen

Hier kommt der spaßige Teil: Wir rufen die Website-URL ab und verwenden sie innerhalb der Komponente.

import React from 'react';
import Helmet from 'react-helmet';
import useSiteMetadata from '../hooks/use-site-metadata';

const Page = ({ location }) => {
  const { siteURL } = useSiteMetadata();
  return (
    <Helmet>
      <link rel="canonical" href={`${siteURL}${location.pathname}`} />
    </Helmet>
  );
};

export default Page;

Lassen Sie es uns aufschlüsseln.

In Zeile 3 importieren wir den von uns erstellten useSiteMetadata-Hook in die Komponente.

import useSiteMetadata from '../hooks/use-site-metadata';

Dann, in Zeile 6, destrukturieren wir die Daten, die von dort kommen, und erstellen die Variable siteURL. Jetzt haben wir die Website-URL, die uns während der Build- und Laufzeit zur Verfügung steht. Super!

const { siteURL } = useSiteMetadata();

Kombinieren Sie die Website-URL mit dem Pfad der Seite und fügen Sie sie in das Markup ein

Erinnern Sie sich an die Location-Prop aus der zweiten Methode? Das Tolle daran ist, dass sie sowohl während der Build- als auch zur Laufzeit die pathname-Eigenschaft enthält. Sehen Sie, worauf das hinausläuft? Wir müssen nur die beiden kombinieren

`${siteURL}${location.pathname}`

Dies ist wahrscheinlich die robusteste Lösung, die in Browsern und bei Produktions-Builds funktioniert. Ich persönlich verwende diese Methode am häufigsten.

Ich verwende hier React Helmet in diesem Beispiel. Wenn Sie davon noch nichts gehört haben, ist es ein Werkzeug zum Rendern des Kopfbereichs in React-Anwendungen. Darrell Hoffman hat hier auf CSS-Tricks eine gute Erklärung dazu verfasst.

Methode 4: Generieren Sie die aktuelle Seiten-URL auf der Serverseite

Was?! Haben Sie gerade Server gesagt? Ist Gatsby nicht ein Static Site Generator? Ja, ich habe Server gesagt. Aber es ist kein Server im herkömmlichen Sinne.

Wie wir bereits wissen, generiert Gatsby während der Build-Zeit statische Seiten (d. h. Server-rendert sie). Daher kommt der Name. Das Tolle daran ist, dass wir mit mehreren APIs, die Gatsby bereits bereitstellt, in diesen Prozess eingreifen können.

Die API, die uns am meisten interessiert, heißt onRenderBody. Meistens wird sie verwendet, um benutzerdefinierte Skripte und Stile zur Seite einzufügen. Aber das Aufregende daran (und an anderen serverseitigen APIs) ist, dass sie einen pathname-Parameter hat. Das bedeutet, dass wir die aktuelle Seiten-URL "auf dem Server" generieren können.

Ich persönlich würde diese Methode nicht verwenden, um Meta-Tags in den Kopfbereich einzufügen, da die dritte Methode, die wir betrachtet haben, dafür besser geeignet ist. Aber nur zum Beispiel, lassen Sie mich Ihnen zeigen, wie Sie den kanonischen Link zur Website mit onRenderBody hinzufügen könnten.

Um eine serverseitige API zu verwenden, müssen Sie den Code in einer Datei namens gatsby-ssr.js schreiben, die sich im Stammordner Ihrer Website befindet. Um den Link in den Kopfbereich einzufügen, würden Sie Folgendes schreiben

const React = require('react');
const config = require('./gatsby-config');

exports.onRenderBody = ({ pathname, setHeadComponents }) => {
  setHeadComponents([
    <link rel="canonical" href={`${config.siteMetadata.siteURL}${pathname}`} />,
  ]);
};

Lassen Sie uns diesen Code Stück für Stück aufschlüsseln.

Wir benötigen React in Zeile 1. Das ist notwendig, damit die JSX-Syntax funktioniert. Dann, in Zeile 2, ziehen wir Daten aus der Datei gatsby-config.js in eine Variable config.

Als Nächstes rufen wir die Methode setHeadComponents innerhalb von onRenderBody auf und übergeben ihr ein Array von Komponenten, die dem Website-Header hinzugefügt werden sollen. In unserem Fall ist es nur ein Link-Tag. Und für das href-Attribut des Links selbst kombinieren wir siteURL und pathname

`${config.siteMetadata.siteURL}${pathname}`

Wie ich bereits sagte, ist dies wahrscheinlich nicht die bevorzugte Methode zum Hinzufügen von Tags zum Kopfbereich, aber es ist gut zu wissen, dass Gatsby serverseitige APIs hat, die es ermöglichen, eine URL für jede gegebene Seite während der Server-Rendering-Phase zu generieren.

Wenn Sie mehr über Server-Side Rendering mit Gatsby erfahren möchten, empfehle ich Ihnen, die offizielle Dokumentation zu lesen.

Das ist alles!

Wie Sie sehen, ist das Abrufen der URL der aktuellen Seite in Gatsby nicht sehr kompliziert, besonders wenn man die Kernkonzepte versteht und die verfügbaren Werkzeuge kennt. Wenn Sie andere Methoden kennen, lassen Sie es mich bitte in den Kommentaren wissen!

Ressourcen