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
- Fügen Sie die Eigenschaft
siteURLzusiteMetadataingatsby-config.jshinzu. - Erstellen Sie einen Static Query Hook, um
siteMetadatain jeder Komponente abzurufen. - Verwenden Sie diesen Hook, um
siteURLabzurufen. - 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!
Jesus, das ist viel JS, nur um auf die Seiten-URL zuzugreifen. Das ist in den meisten anderen SSGs buchstäblich nur {{ page.url }}.
Hallo Max! Ja, ich verstehe dich, es sieht nach viel Code für eine so einfache Aufgabe aus. Aber in Wirklichkeit verwendet man meistens eine Variation von
`${siteURL}${location.pathname}`. Es ist nur eine Frage des Verständnisses, woher diese Teile kommen.Hallo, vielen Dank. Ich habe damit gekämpft und bin bei den gleichen Lösungen wie Ihre Nr. 3 gelandet. Insbesondere muss ich sowieso siteMetadata.siteUrl setzen, um gatsby-plugin-sitemap verwenden zu können.
Danke, Paulina! Ja, das ist normalerweise meine bevorzugte Methode. Ich verwende
siteMetadataselbst für eine ganze Reihe von Dingen!danke, Mann!
Danke für den Beitrag,
so ein schöner Beitrag…
Gatsby verwendet React Router im Hintergrund, sodass Sie auch die Location RenderProp verwenden könnten.
Hallo, ich habe die 3. Methode befolgt, aber sie hat bei mir nicht funktioniert. Mit dieser Zeile: const url =
${site.siteMetadata.siteURL}${location.pathname}funktionierte es lokal, aber auf Netlify heißt es: Fehler "location" ist während des serverseitigen Renderings nicht verfügbar. Es scheint also nicht immer zu funktionieren.Können wir nicht
${location.origin}${location.pathname}verwenden??Hallo zusammen, ich habe die Kurzform herausgefunden, das übergibt einen Booleschen Wert an meine Navbar.
Ich liebe euch alle
<NavbarisIndex={props=>(props.location.pathname === "/" ? true : false)}
/>
Falls Sie erwarten, dass #4 lokal funktioniert, wird das nicht der Fall sein. Siehe hier: https://github.com/gatsbyjs/gatsby/issues/4350#issuecomment-370182332
Wenn Sie auf Netlify oder so etwas bereitstellen, sollte es in Ordnung sein, wenn Sie eine Seite direkt besuchen oder navigieren und aktualisieren.
Wenn Sie Netlify verwenden, könnte dies hilfreich sein: Ich kann domain() für meine
<helmet>Social Sharing Tags und andere Sharing-Szenarien verwenden. Die Methode gibt die Testdomäne (Branch Deploy) von Netlify oder die konfigurierte Hauptdomäne zurück. Als Fallback für Hydrationsfälle (was bedeutet, dass wir einen Browser haben) verwendet sie den Hostnamen des Browsers.https://github.com/FixMyBerlin/fixmy.safetycheck/blob/develop/src/components/utils/domain.ts