Firebase in eine Next.js-App einbinden

1. Hinweis

In diesem Codelab erfahren Sie, wie Sie Firebase in die Next.js-Web-App Friendly Eats einbinden. Hierbei handelt es sich um eine Website für Restaurantbewertungen.

Friendly Eats-Webanwendung

Die fertige Webanwendung bietet nützliche Funktionen, die zeigen, wie Sie mit Firebase Next.js-Apps erstellen können. Zu diesen Funktionen gehören:

  • Automatischer Build und automatische Bereitstellung: In diesem Codelab wird Firebase App Hosting verwendet, um Ihren Next.js-Code jedes Mal automatisch zu erstellen und bereitzustellen, wenn Sie einen Commit auf einen konfigurierten Branch ausführen.
  • An- und Abmelden:Mit der fertigen Web-App können Sie sich über Google an- und abmelden. Nutzeranmeldung und Persistenz werden vollständig über Firebase Authentication verwaltet.
  • Bilder: In der fertigen Webanwendung können angemeldete Nutzer Bilder von Restaurants hochladen. Bild-Assets werden in Cloud Storage for Firebase gespeichert. Das Firebase JavaScript SDK stellt eine öffentliche URL zu hochgeladenen Bildern bereit. Diese öffentliche URL wird dann im entsprechenden Restaurantdokument in Cloud Firestore gespeichert.
  • Rezensionen: In der fertigen Web-App können angemeldete Nutzer Rezensionen zu Restaurants posten, die aus einer Sternebewertung und einer textbasierten Nachricht bestehen. Überprüfungsinformationen werden in Cloud Firestore gespeichert.
  • Filter: In der fertigen Web-App können angemeldete Nutzer die Liste der Restaurants nach Kategorie, Standort und Preis filtern. Sie können auch die verwendete Sortiermethode anpassen. Der Zugriff auf Daten erfolgt über Cloud Firestore und Firestore-Abfragen werden basierend auf den verwendeten Filtern angewendet.

Vorbereitung

  • Ein GitHub-Konto
  • Kenntnisse in Next.js und JavaScript

Lerninhalte

  • Firebase mit dem Next.js App Router und serverseitigem Rendering verwenden
  • So speichern Sie Images in Cloud Storage for Firebase dauerhaft.
  • Daten in einer Cloud Firestore-Datenbank lesen und schreiben
  • Hier erfahren Sie, wie Sie die Anmeldung über Google mit dem Firebase JavaScript SDK verwenden.

Voraussetzungen

  • Git
  • Eine aktuelle stabile Version von Node.js
  • Browser Ihrer Wahl, z. B. Google Chrome
  • Eine Entwicklungsumgebung mit einem Code-Editor und einem Terminal
  • Ein Google-Konto zum Erstellen und Verwalten Ihres Firebase-Projekts
  • Sie können Ihr Firebase-Projekt auf den Blaze-Tarif umstellen.

2. Entwicklungsumgebung und GitHub-Repository einrichten

Dieses Codelab enthält die Starter-Codebasis der App und basiert auf der Firebase CLI.

GitHub-Repository erstellen

Den Quellcode des Codelab finden Sie unter https://github.com/firebase/Friendlyeats-web. Das Repository enthält Beispielprojekte für mehrere Plattformen. In diesem Codelab wird jedoch nur das Verzeichnis nextjs-start verwendet. Beachten Sie die folgenden Verzeichnisse:

* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.

Kopieren Sie den Ordner nextjs-start in Ihr eigenes Repository:

  1. Erstellen Sie über ein Terminal einen neuen Ordner auf Ihrem Computer und wechseln Sie in das neue Verzeichnis:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. Verwenden Sie das npm-Paket giget, um nur den Ordner nextjs-start abzurufen:
    npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
    
  3. Verfolgen Sie Änderungen lokal mit Git:
    git init
    
    git commit -a -m "codelab starting point"
    
    git branch -M main
    
  4. Erstellen Sie ein neues GitHub-Repository: https://github.com/new. Sie können ihm einen beliebigen Namen geben.
    1. Sie erhalten von GitHub eine neue Repository-URL, die entweder https://github.com//.git oder git@github.com:/.git lautet. Kopieren Sie diese URL.
  5. Übertragen Sie lokale Änderungen per Push in Ihr neues GitHub-Repository. Führen Sie den folgenden Befehl aus und ersetzen Sie dabei die Repository-URL durch den Platzhalter .
    git remote add origin <your-repository-url>
    
    git push -u origin main
    
  6. Der Startcode sollte jetzt in Ihrem GitHub-Repository angezeigt werden.

Firebase CLI installieren oder aktualisieren

Führen Sie den folgenden Befehl aus, um zu prüfen, ob die Firebase CLI installiert ist und Version 13.9.0 oder höher installiert ist:

firebase --version

Wenn eine niedrigere Version angezeigt wird oder Firebase CLI nicht installiert ist, führen Sie den Installationsbefehl aus:

npm install -g firebase-tools@latest

Wenn Sie die Firebase CLI aufgrund von Berechtigungsfehlern nicht installieren können, lesen Sie die npm-Dokumentation oder verwenden Sie eine andere Installationsoption.

In Firebase anmelden

  1. Führen Sie den folgenden Befehl aus, um sich in der Firebase CLI anzumelden:
    firebase login
    
  2. Geben Sie Y oder N ein, je nachdem, ob Firebase Daten erheben soll.
  3. Wählen Sie im Browser Ihr Google-Konto aus und klicken Sie dann auf Zulassen.

3. Das Firebase-Projekt einrichten

In diesem Abschnitt richten Sie ein Firebase-Projekt ein und verknüpfen damit eine Firebase-Web-App. Außerdem richten Sie die Firebase-Dienste ein, die von der Beispiel-Web-App verwendet werden.

Firebase-Projekt erstellen

  1. Klicken Sie in der Firebase Console auf Projekt hinzufügen.
  2. Geben Sie im Textfeld Projektnamen eingeben FriendlyEats Codelab (oder einen beliebigen Projektnamen) ein und klicken Sie auf Weiter.
  3. Bestätigen Sie im modalen Fenster Firebase-Tarif bestätigen, dass es sich um Blaze handelt, und klicken Sie dann auf Tarif bestätigen.
  4. Für dieses Codelab benötigen Sie kein Google Analytics. Deaktivieren Sie daher die Option Google Analytics für dieses Projekt aktivieren.
  5. Klicken Sie auf Projekt erstellen.
  6. Warten Sie, bis Ihr Projekt bereitgestellt wurde, und klicken Sie dann auf Weiter.
  7. Rufen Sie in Ihrem Firebase-Projekt die Projekteinstellungen auf. Notieren Sie sich Ihre Projekt-ID, da Sie diese später benötigen. Anhand dieser eindeutigen Kennung wird Ihr Projekt identifiziert, z. B. in der Firebase CLI.

Firebase-Preismodell upgraden

Wenn Sie Firebase App Hosting und Cloud Storage for Firebase verwenden möchten, muss für Ihr Firebase-Projekt das „Pay as you go“-Preismodell (Blaze) verwendet werden. Das bedeutet, dass es mit einem Cloud-Rechnungskonto verknüpft ist.

  • Für ein Cloud-Rechnungskonto ist eine Zahlungsmethode erforderlich, z. B. eine Kreditkarte.
  • Wenn Sie neu bei Firebase und Google Cloud sind, prüfen Sie, ob Sie Anspruch auf ein Guthaben in Höhe von 300 $ und ein kostenloses Cloud Billing-Konto haben.
  • Wenn Sie dieses Codelab im Rahmen einer Veranstaltung absolvieren, fragen Sie Ihren Organisator, ob Cloud-Guthaben verfügbar ist.

So führen Sie ein Upgrade auf den Blaze-Tarif durch:

  1. Wählen Sie in der Firebase Console Tarif upgraden aus.
  2. Wählen Sie den Tarif „Blaze“ aus. Folgen Sie der Anleitung auf dem Bildschirm, um ein Cloud-Rechnungskonto mit Ihrem Projekt zu verknüpfen.
    Wenn Sie im Rahmen dieses Upgrades ein Cloud-Rechnungskonto erstellen mussten, müssen Sie möglicherweise zum Upgradevorgang in der Firebase Console zurückkehren, um das Upgrade abzuschließen.

Ihrem Firebase-Projekt eine Web-App hinzufügen

  1. Rufen Sie in Ihrem Firebase-Projekt die Projektübersicht auf und klicken Sie dann auf e41f2efdd9539c31.png Web.

    Wenn in Ihrem Projekt bereits Apps registriert sind, klicken Sie auf App hinzufügen, um das Websymbol zu sehen.
  2. Geben Sie im Textfeld App-Alias einen einprägsamen Alias für die App ein, z. B. My Next.js app.
  3. Lassen Sie das Kästchen Richten Sie außerdem Firebase Hosting für diese App ein deaktiviert.
  4. Klicken Sie auf App registrieren > Weiter > Weiter > Weiter zur Konsole.

Firebase-Dienste in der Firebase Console einrichten

Authentifizierung einrichten

  1. Gehen Sie in der Firebase Console zu Authentifizierung.
  2. Klicken Sie auf Starten.
  3. Klicken Sie in der Spalte Zusätzliche Anbieter auf Google > Aktivieren.
  4. Geben Sie im Textfeld Öffentlicher Name für Projekt einen einprägsamen Namen wie My Next.js app ein.
  5. Wählen Sie im Drop-down-Menü Support-E-Mail-Adresse für das Projekt Ihre E-Mail-Adresse aus.
  6. Klicken Sie auf Speichern.

Cloud Firestore einrichten

  1. Maximieren Sie im linken Bereich der Firebase Console Build und wählen Sie dann Firestore-Datenbank aus.
  2. Klicken Sie auf Datenbank erstellen.
  3. Lassen Sie die Datenbank-ID auf (default).
  4. Wählen Sie einen Speicherort für die Datenbank aus und klicken Sie auf Weiter.
    Für eine echte App sollten Sie einen Speicherort in der Nähe Ihrer Nutzer auswählen.
  5. Klicken Sie auf Im Testmodus starten. Lesen Sie den Haftungsausschluss zu den Sicherheitsregeln.
    Später in diesem Codelab fügen Sie Sicherheitsregeln hinzu, um Ihre Daten zu schützen. Veröffentlichen oder verteilen Sie keine App, ohne Sicherheitsregeln für Ihre Datenbank hinzuzufügen.
  6. Klicken Sie auf Erstellen.

Cloud Storage for Firebase einrichten

  1. Maximieren Sie im linken Bereich der Firebase Console die Option Build und wählen Sie dann Storage aus.
  2. Klicken Sie auf Starten.
  3. Wählen Sie einen Speicherort für Ihren Standard-Storage-Bucket aus.
    Buckets in US-WEST1, US-CENTRAL1 und US-EAST1 können die Stufe „Immer kostenlos“ für Google Cloud Storage nutzen. Für Buckets an allen anderen Speicherorten gelten die Preise und Nutzungsbedingungen für Google Cloud Storage.
  4. Klicken Sie auf Im Testmodus starten. Lesen Sie den Haftungsausschluss zu den Sicherheitsregeln.
    Später in diesem Codelab fügen Sie Sicherheitsregeln hinzu, um Ihre Daten zu schützen. Veröffentlichen oder verteilen Sie keine App, ohne Sicherheitsregeln für Ihren Speicher-Bucket hinzuzufügen.
  5. Klicken Sie auf Erstellen.

4. Starter-Codebasis ansehen

In diesem Abschnitt sehen Sie sich einige Bereiche der Startcodebasis der App an, denen Sie in diesem Codelab Funktionen hinzufügen.

Ordner- und Dateistruktur

Die folgende Tabelle enthält einen Überblick über die Ordner- und Dateistruktur der App:

Ordner und Dateien

Beschreibung

src/components

React-Komponenten für Filter, Überschriften, Restaurantdetails und Rezensionen

src/lib

Dienstprogrammfunktionen, die nicht unbedingt an React oder Next.js gebunden sind

src/lib/firebase

Firebase-spezifischer Code und Firebase-Konfiguration

public

Statische Assets in der Web-App, z. B. Symbole

src/app

Routing mit dem Next.js App Router

src/app/restaurant

Einen API-Route-Handler

package.json und package-lock.json

Projektabhängigkeiten mit npm

next.config.js

Next.js-spezifische Konfiguration (Serveraktionen sind aktiviert)

jsconfig.json

Konfiguration des JavaScript-Sprachdienstes

Server- und Clientkomponenten

Die App ist eine Next.js-Web-App, die den App Router verwendet. Das serverseitige Rendering wird in der gesamten App verwendet. Die Datei src/app/page.js ist beispielsweise eine Serverkomponente, die für die Startseite verantwortlich ist. Die Datei src/components/RestaurantListings.jsx ist eine Clientkomponente, die durch die Anweisung "use client" am Anfang der Datei angegeben wird.

Importanweisungen

Möglicherweise sehen Sie Importanweisungen wie die folgenden:

import RatingPicker from "@/src/components/RatingPicker.jsx";

In der App wird das Symbol @ verwendet, um unübersichtliche relative Importpfade zu vermeiden. Dies wird durch Pfadaliasse ermöglicht.

Firebase-spezifische APIs

Der gesamte Firebase API-Code wird im Verzeichnis src/lib/firebase verpackt. Einzelne React-Komponenten importieren dann die verpackten Funktionen aus dem Verzeichnis src/lib/firebase, anstatt Firebase-Funktionen direkt zu importieren.

Beispieldaten

Die Daten zu fiktiven Restaurants und Rezensionen sind in der Datei src/lib/randomData.js enthalten. Die Daten aus dieser Datei werden im Code in der Datei src/lib/fakeRestaurants.js zusammengestellt.

5. App-Hosting-Backend erstellen

In diesem Abschnitt richten Sie ein App Hosting-Backend ein, um einen Zweig in Ihrem Git-Repository zu beobachten.

Am Ende dieses Abschnitts haben Sie ein App Hosting-Backend, das mit Ihrem Repository in GitHub verbunden ist und automatisch eine neue Version Ihrer App neu erstellt und bereitstellt, wenn Sie einen neuen Commit an Ihren main-Branch übertragen.

Sicherheitsregeln bereitstellen

Der Code enthält bereits Sicherheitsregeln für Firestore und Cloud Storage for Firebase. Nach der Bereitstellung der Sicherheitsregeln sind die Daten in Ihrer Datenbank und Ihrem Bucket besser vor Missbrauch geschützt.

  1. Konfigurieren Sie in Ihrem Terminal die Befehlszeile, um das zuvor erstellte Firebase-Projekt zu verwenden:
    firebase use --add
    
    Geben Sie bei Aufforderung nach einem Alias friendlyeats-codelab ein.
  2. Führen Sie den folgenden Befehl in Ihrem Terminal aus, um diese Sicherheitsregeln bereitzustellen:
    firebase deploy --only firestore:rules,storage
    
  3. Wenn Sie gefragt werden: "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?", drücken Sie Enter, um Ja auszuwählen.

Firebase-Konfiguration in den Code Ihrer Webanwendung einfügen

  1. Rufen Sie in der Firebase Console die Projekteinstellungen auf.
  2. Klicken Sie im Bereich SDK-Einrichtung und -Konfiguration auf „App hinzufügen“ und dann auf das Symbol mit den eckigen Klammern , um eine neue Web-App zu registrieren.
  3. Kopieren Sie am Ende des Erstellungsvorgangs für die Web-App die Variable firebaseConfig und kopieren Sie ihre Eigenschaften und ihre Werte.
  4. Öffnen Sie die Datei apphosting.yaml in Ihrem Code-Editor und tragen Sie die Werte der Umgebungsvariablen mit den Konfigurationswerten aus der Firebase Console ein.
  5. Ersetzen Sie in der Datei die vorhandenen Properties durch die kopierten.
  6. Speichern Sie die Datei.

Backend erstellen

  1. Rufen Sie in der Firebase Console die Seite App-Hosting auf:

Nullstatus der App Hosting-Konsole mit der Schaltfläche „Jetzt starten“

  1. Klicken Sie auf „Jetzt starten“, um mit dem Erstellen des Back-Ends zu beginnen. Konfigurieren Sie Ihr Backend so:
  2. Folgen Sie der Anleitung im ersten Schritt, um das zuvor erstellte GitHub-Repository zu verbinden.
  3. Legen Sie die Bereitstellungseinstellungen fest:
    1. Stammverzeichnis bei / belassen
    2. Legen Sie den Live-Zweig auf main fest.
    3. Automatische Roll-outs aktivieren
  4. Benennen Sie das Backend friendlyeats-codelab.
  5. Wählen Sie unter „Firebase Web-App erstellen oder verknüpfen“ die Web-App aus, die Sie zuvor aus dem Drop-down-Menü „Vorhandene Firebase Web-App auswählen“ konfiguriert haben.
  6. Klicken Sie auf „Fertigstellen und bereitstellen“. Nach kurzer Zeit werden Sie auf eine neue Seite weitergeleitet, auf der Sie den Status Ihres neuen App Hosting-Backends sehen können.
  7. Klicken Sie nach Abschluss der Einführung unter „Domains“ auf Ihre kostenlose Domain. Aufgrund der DNS-Weitergabe kann es einige Minuten dauern, bis dies funktioniert.

Sie haben die erste Webanwendung bereitgestellt. Jedes Mal, wenn Sie per Push einen neuen Commit an den main-Zweig Ihres GitHub-Repositorys senden, werden in der Firebase Console ein neuer Build und ein Roll-out gestartet. Ihre Website wird nach Abschluss des Roll-outs automatisch aktualisiert.

6. Authentifizierung für die Webanwendung hinzufügen

In diesem Abschnitt fügen Sie der Webanwendung eine Authentifizierung hinzu, damit Sie sich darin anmelden können.

Anmelde- und Abmeldefunktionen implementieren

  1. Ersetzen Sie in der Datei src/lib/firebase/auth.js die Funktionen onAuthStateChanged, signInWithGoogle und signOut durch den folgenden Code:
export function onAuthStateChanged(cb) {
	return _onAuthStateChanged(auth, cb);
}

export async function signInWithGoogle() {
  const provider = new GoogleAuthProvider();

  try {
    await signInWithPopup(auth, provider);
  } catch (error) {
    console.error("Error signing in with Google", error);
  }
}

export async function signOut() {
  try {
    return auth.signOut();
  } catch (error) {
    console.error("Error signing out with Google", error);
  }
}

In diesem Code werden die folgenden Firebase APIs verwendet:

Firebase API

Beschreibung

GoogleAuthProvider

Erstellt eine Instanz des Google-Authentifizierungsanbieters.

signInWithPopup

Startet einen dialogbasierten Authentifizierungsvorgang.

auth.signOut

Der Nutzer wird abgemeldet.

In der Datei src/components/Header.jsx ruft der Code bereits die Funktionen signInWithGoogle und signOut auf.

  1. Erstellen Sie einen Commit mit der Commit-Nachricht „Google-Authentifizierung hinzufügen“ und pushen Sie ihn in Ihr GitHub-Repository. 1. Öffnen Sie in der Firebase Console die Seite App Hosting und warten Sie, bis die neue Einführung abgeschlossen ist.
  2. Aktualisieren Sie die Seite in der Webanwendung und klicken Sie auf Über Google anmelden. Die Webanwendung wird nicht aktualisiert, sodass nicht klar ist, ob die Anmeldung erfolgreich war.

Authentifizierungsstatus an Server senden

Um den Authentifizierungsstatus an den Server weiterzugeben, verwenden wir einen Dienst-Worker. Ersetzen Sie die Funktionen fetchWithFirebaseHeaders und getAuthIdToken durch den folgenden Code:

async function fetchWithFirebaseHeaders(request) {
  const app = initializeApp(firebaseConfig);
  const auth = getAuth(app);
  const installations = getInstallations(app);
  const headers = new Headers(request.headers);
  const [authIdToken, installationToken] = await Promise.all([
    getAuthIdToken(auth),
    getToken(installations),
  ]);
  headers.append("Firebase-Instance-ID-Token", installationToken);
  if (authIdToken) headers.append("Authorization", `Bearer ${authIdToken}`);
  const newRequest = new Request(request, { headers });
  return await fetch(newRequest);
}

async function getAuthIdToken(auth) {
  await auth.authStateReady();
  if (!auth.currentUser) return;
  return await getIdToken(auth.currentUser);
}

Authentifizierungsstatus auf dem Server lesen

Wir verwenden FirebaseServerApp, um den Authentifizierungsstatus des Clients auf dem Server zu spiegeln.

Öffnen Sie src/lib/firebase/serverApp.js und ersetzen Sie die Funktion getAuthenticatedAppForUser:

export async function getAuthenticatedAppForUser() {
  const idToken = headers().get("Authorization")?.split("Bearer ")[1];
  console.log('firebaseConfig', JSON.stringify(firebaseConfig));
  const firebaseServerApp = initializeServerApp(
    firebaseConfig,
    idToken
      ? {
          authIdToken: idToken,
        }
      : {}
  );

  const auth = getAuth(firebaseServerApp);
  await auth.authStateReady();

  return { firebaseServerApp, currentUser: auth.currentUser };
}

Benachrichtigungen zu Authentifizierungsänderungen abonnieren

So abonnieren Sie Authentifizierungsänderungen:

  1. Rufen Sie die Datei src/components/Header.jsx auf.
  2. Ersetzen Sie die Funktion useUserSession durch den folgenden Code:
function useUserSession(initialUser) {
	// The initialUser comes from the server via a server component
	const [user, setUser] = useState(initialUser);
	const router = useRouter();

	// Register the service worker that sends auth state back to server
	// The service worker is built with npm run build-service-worker
	useEffect(() => {
		if ("serviceWorker" in navigator) {
			const serializedFirebaseConfig = encodeURIComponent(JSON.stringify(firebaseConfig));
			const serviceWorkerUrl = `/auth-service-worker.js?firebaseConfig=${serializedFirebaseConfig}`
		
		  navigator.serviceWorker
			.register(serviceWorkerUrl)
			.then((registration) => console.log("scope is: ", registration.scope));
		}
	  }, []);

	useEffect(() => {
		const unsubscribe = onAuthStateChanged((authUser) => {
			setUser(authUser)
		})

		return () => unsubscribe()
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	useEffect(() => {
		onAuthStateChanged((authUser) => {
			if (user === undefined) return

			// refresh when user changed to ease testing
			if (user?.email !== authUser?.email) {
				router.refresh()
			}
		})
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, [user])

	return user;
}

In diesem Code wird ein State-Hook von React verwendet, um den Nutzer zu aktualisieren, wenn die onAuthStateChanged-Funktion angibt, dass sich der Authentifizierungsstatus geändert hat.

Änderungen prüfen

Das Stamm-Layout in der src/app/layout.js-Datei rendert den Header und gibt den Nutzer, falls verfügbar, als Prop weiter.

<Header initialUser={currentUser?.toJSON()} />

Das bedeutet, dass die Komponente „<Header>“ Nutzerdaten, sofern verfügbar, während der Serverlaufzeit rendert. Wenn nach dem ersten Seitenaufbau während des Seitenlebenszyklus Authentifizierungsaktualisierungen auftreten, werden diese vom onAuthStateChanged-Handler verarbeitet.

Jetzt ist es an der Zeit, einen neuen Build einzuführen und zu prüfen, was Sie erstellt haben.

  1. Erstellen Sie einen Commit mit der Commit-Nachricht „Anmeldestatus anzeigen“ und übertragen Sie ihn per Push in Ihr GitHub-Repository.
  2. Öffnen Sie in der Firebase Console die Seite App Hosting und warten Sie, bis die neue Einführung abgeschlossen ist.
  3. Überprüfen Sie das neue Authentifizierungsverhalten:
    1. Aktualisieren Sie die Web-App im Browser. Ihr Anzeigename wird in der Kopfzeile angezeigt.
    2. Melden Sie sich ab und wieder an. Die Seite wird in Echtzeit und ohne Aktualisierung der Seite aktualisiert. Sie können diesen Schritt mit verschiedenen Nutzern wiederholen.
    3. Optional: Klicken Sie mit der rechten Maustaste auf die Web-App, wählen Sie Seitenquelltext anzeigen aus und suchen Sie nach dem Anzeigenamen. Er erscheint in der HTML-Rohquelle, die vom Server zurückgegeben wird.

7. Restaurantinformationen ansehen

Die Web-App enthält Beispieldaten für Restaurants und Rezensionen.

Ein oder mehrere Restaurants hinzufügen

So fügen Sie simulierte Restaurantdaten in Ihre lokale Cloud Firestore-Datenbank ein:

  1. Wählen Sie in der Webanwendung 2cf67d488d8e6332.png > Beispielrestaurants hinzufügen aus.
  2. Wählen Sie in der Firebase Console auf der Seite Firestore-Datenbank die Option restaurants aus. Sie sehen die Dokumente der obersten Ebene in der Sammlung „Restaurants“, die jeweils ein Restaurant repräsentieren.
  3. Klicken Sie auf einige Dokumente, um die Eigenschaften eines Restaurantdokuments zu sehen.

Liste der Restaurants anzeigen

Ihre Cloud Firestore-Datenbank enthält jetzt Restaurants, die von der Next.js-Webanwendung angezeigt werden können.

So definieren Sie den Code zum Abrufen von Daten:

  1. Suchen Sie in der Datei src/app/page.js nach der Serverkomponente <Home /> und prüfen Sie den Aufruf der Funktion getRestaurants, die bei der Serverausführung eine Liste von Restaurants abruft. In den folgenden Schritten implementieren Sie die Funktion getRestaurants.
  2. Ersetzen Sie in der Datei src/lib/firebase/firestore.js die Funktionen applyQueryFilters und getRestaurants durch den folgenden Code:
function applyQueryFilters(q, { category, city, price, sort }) {
	if (category) {
		q = query(q, where("category", "==", category));
	}
	if (city) {
		q = query(q, where("city", "==", city));
	}
	if (price) {
		q = query(q, where("price", "==", price.length));
	}
	if (sort === "Rating" || !sort) {
		q = query(q, orderBy("avgRating", "desc"));
	} else if (sort === "Review") {
		q = query(q, orderBy("numRatings", "desc"));
	}
	return q;
}

export async function getRestaurants(db = db, filters = {}) {
	let q = query(collection(db, "restaurants"));

	q = applyQueryFilters(q, filters);
	const results = await getDocs(q);
	return results.docs.map(doc => {
		return {
			id: doc.id,
			...doc.data(),
			// Only plain objects can be passed to Client Components from Server Components
			timestamp: doc.data().timestamp.toDate(),
		};
	});
}
  1. Erstellen Sie einen Commit mit der Commit-Nachricht „Liste der Restaurants aus Firestore lesen“ und pushen Sie ihn in Ihr GitHub-Repository.
  2. Öffnen Sie in der Firebase Console die Seite App Hosting und warten Sie, bis die neue Einführung abgeschlossen ist.
  3. Aktualisieren Sie die Seite in der Webanwendung. Restaurantbilder werden auf der Seite als Kacheln angezeigt.

Prüfen, ob die Restauranteinträge zur Laufzeit des Servers geladen werden

Bei Verwendung des Next.js-Frameworks ist es möglicherweise nicht offensichtlich, wenn Daten zur Server- oder clientseitigen Laufzeit geladen werden.

So prüfen Sie, ob Restauranteinträge zur Serverlaufzeit geladen werden:

  1. Öffnen Sie in der Webanwendung die Entwicklertools und deaktivieren Sie JavaScript.

JavaScipt in den Entwicklertools deaktivieren

  1. Aktualisieren Sie die Webanwendung. Die Restauranteinträge werden weiterhin geladen. Die Restaurantinformationen werden in der Serverantwort zurückgegeben. Wenn JavaScript aktiviert ist, werden die Restaurantinformationen über den clientseitigen JavaScript-Code hydriert.
  2. Aktivieren Sie JavaScript in den Entwicklertools wieder.

Mit Cloud Firestore-Snapshot-Listenern auf Restaurantupdates warten

Im vorherigen Abschnitt haben Sie gesehen, wie die ersten Restaurants aus der Datei src/app/page.js geladen wurden. Die src/app/page.js-Datei ist eine Serverkomponente und wird auf dem Server gerendert, einschließlich des Firebase-Codes zum Abrufen von Daten.

Die src/components/RestaurantListings.jsx-Datei ist eine Clientkomponente und kann so konfiguriert werden, dass serverseitig gerendertes Markup hydratisiert wird.

So konfigurierst du die Datei src/components/RestaurantListings.jsx für die Bereitstellung des vom Server gerenderten Markups:

  1. Sehen Sie sich in der Datei src/components/RestaurantListings.jsx den folgenden Code an, der bereits für Sie geschrieben ist:
useEffect(() => {
        const unsubscribe = getRestaurantsSnapshot(data => {
                setRestaurants(data);
        }, filters);

        return () => {
                unsubscribe();
        };
}, [filters]);

Dieser Code ruft die Funktion getRestaurantsSnapshot() auf, die der Funktion getRestaurants() ähnelt, die Sie in einem vorherigen Schritt implementiert haben. Diese Snapshot-Funktion bietet jedoch einen Callback-Mechanismus, sodass der Callback jedes Mal aufgerufen wird, wenn eine Änderung an der Sammlung des Restaurants vorgenommen wird.

  1. Ersetzen Sie in der Datei src/lib/firebase/firestore.js die Funktion getRestaurantsSnapshot() durch den folgenden Code:
export function getRestaurantsSnapshot(cb, filters = {}) {
	if (typeof cb !== "function") {
		console.log("Error: The callback parameter is not a function");
		return;
	}

	let q = query(collection(db, "restaurants"));
	q = applyQueryFilters(q, filters);

	const unsubscribe = onSnapshot(q, querySnapshot => {
		const results = querySnapshot.docs.map(doc => {
			return {
				id: doc.id,
				...doc.data(),
				// Only plain objects can be passed to Client Components from Server Components
				timestamp: doc.data().timestamp.toDate(),
			};
		});

		cb(results);
	});

	return unsubscribe;
}

Änderungen, die über die Seite Firestore-Datenbank vorgenommen werden, werden jetzt in Echtzeit in der Webanwendung angezeigt.

  1. Erstellen Sie einen Commit mit der Commit-Nachricht „Für Echtzeitaktualisierungen von Restaurants sorgen“ und pushen Sie ihn in Ihr GitHub-Repository.
  2. Öffnen Sie in der Firebase Console die Seite App Hosting und warten Sie, bis die neue Einführung abgeschlossen ist.
  3. Wählen Sie in der Webanwendung 27ca5d1e8ed8adfe.png > Beispielrestaurants hinzufügen aus. Wenn die Snapshot-Funktion richtig implementiert ist, werden die Restaurants ohne Aktualisierung der Seite in Echtzeit angezeigt.

8. Von Nutzern eingereichte Rezensionen aus der Webanwendung speichern

  1. Ersetzen Sie in der Datei src/lib/firebase/firestore.js die Funktion updateWithRating() durch den folgenden Code:
const updateWithRating = async (
	transaction,
	docRef,
	newRatingDocument,
	review
) => {
	const restaurant = await transaction.get(docRef);
	const data = restaurant.data();
	const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
	const newSumRating = (data?.sumRating || 0) + Number(review.rating);
	const newAverage = newSumRating / newNumRatings;

	transaction.update(docRef, {
		numRatings: newNumRatings,
		sumRating: newSumRating,
		avgRating: newAverage,
	});

	transaction.set(newRatingDocument, {
		...review,
		timestamp: Timestamp.fromDate(new Date()),
	});
};

Mit diesem Code wird ein neues Firestore-Dokument eingefügt, das die neue Rezension darstellt. Außerdem aktualisiert der Code das vorhandene Firestore-Dokument, das das Restaurant darstellt, mit aktualisierten Zahlen für die Anzahl der Bewertungen und die durchschnittlich berechnete Bewertung.

  1. Ersetzen Sie die Funktion addReviewToRestaurant() durch den folgenden Code:
export async function addReviewToRestaurant(db, restaurantId, review) {
	if (!restaurantId) {
		throw new Error("No restaurant ID has been provided.");
	}

	if (!review) {
		throw new Error("A valid review has not been provided.");
	}

	try {
		const docRef = doc(collection(db, "restaurants"), restaurantId);
		const newRatingDocument = doc(
			collection(db, `restaurants/${restaurantId}/ratings`)
		);

		// corrected line
		await runTransaction(db, transaction =>
			updateWithRating(transaction, docRef, newRatingDocument, review)
		);
	} catch (error) {
		console.error(
			"There was an error adding the rating to the restaurant",
			error
		);
		throw error;
	}
}

Next.js-Serveraktion implementieren

Eine Next.js-Serveraktion bietet eine praktische API für den Zugriff auf Formulardaten, z. B. data.get("text"), um den Textwert aus der Formulareinreichungsnutzlast abzurufen.

So verwenden Sie eine Next.js-Serveraktion zum Senden des Überprüfungsformulars:

  1. Suchen Sie in der Datei src/components/ReviewDialog.jsx im Element <form> nach dem Attribut action.
<form action={handleReviewFormSubmission}>

Der action-Attributwert bezieht sich auf eine Funktion, die Sie im nächsten Schritt implementieren.

  1. Ersetzen Sie in der Datei src/app/actions.js die Funktion handleReviewFormSubmission() durch den folgenden Code:
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
        const { app } = await getAuthenticatedAppForUser();
        const db = getFirestore(app);

        await addReviewToRestaurant(db, data.get("restaurantId"), {
                text: data.get("text"),
                rating: data.get("rating"),

                // This came from a hidden form field.
                userId: data.get("userId"),
        });
}

Rezensionen für ein Restaurant hinzufügen

Sie haben die Unterstützung für das Einreichen von Rezensionen implementiert und können jetzt prüfen, ob Ihre Rezensionen korrekt in Cloud Firestore eingefügt werden.

So fügen Sie eine Rezension hinzu und prüfen, ob sie in Cloud Firestore eingefügt wurde:

  1. Erstellen Sie einen Commit mit der Commit-Nachricht „Nutzern erlauben, Restaurantbewertungen zu senden“ und übertragen Sie sie per Push in Ihr GitHub-Repository.
  2. Öffnen Sie in der Firebase Console die Seite App-Hosting und warten Sie, bis die neue Bereitstellung abgeschlossen ist.
  3. Aktualisieren Sie die Webanwendung und wählen Sie auf der Startseite ein Restaurant aus.
  4. Klicken Sie auf der Seite des Restaurants auf 3e19beef78bb0d0e.png.
  5. Wählen Sie eine Bewertung aus.
  6. Rezension schreiben.
  7. Klicken Sie auf Senden. Ihre Rezension wird oben in der Liste der Rezensionen angezeigt.
  8. Suchen Sie in Cloud Firestore im Bereich Dokument hinzufügen nach dem Dokument des Restaurants, das Sie bewertet haben, und wählen Sie es aus.
  9. Wählen Sie im Bereich Sammlung starten die Option Bewertungen aus.
  10. Suchen Sie im Bereich Dokument hinzufügen nach dem Dokument, um zu prüfen, ob es wie erwartet eingefügt wurde.

Dokumente im Firestore-Emulator

9. Von Nutzern hochgeladene Dateien aus der Web-App speichern

In diesem Abschnitt fügen Sie eine Funktion hinzu, mit der Sie das mit einem Restaurant verknüpfte Bild ersetzen können, wenn Sie angemeldet sind. Sie laden das Bild in Firebase Storage hoch und aktualisieren die Bild-URL im Cloud Firestore-Dokument, das das Restaurant darstellt.

So speichern Sie von Nutzern hochgeladene Dateien aus der Web-App:

  1. Sehen Sie sich in der Datei src/components/Restaurant.jsx den Code an, der ausgeführt wird, wenn der Nutzer eine Datei hochlädt:
async function handleRestaurantImage(target) {
        const image = target.files ? target.files[0] : null;
        if (!image) {
                return;
        }

        const imageURL = await updateRestaurantImage(id, image);
        setRestaurant({ ...restaurant, photo: imageURL });
}

Es sind keine Änderungen erforderlich. Sie implementieren jedoch das Verhalten der updateRestaurantImage()-Funktion in den folgenden Schritten.

  1. Ersetzen Sie in der Datei src/lib/firebase/storage.js die Funktionen updateRestaurantImage() und uploadImage() durch den folgenden Code:
export async function updateRestaurantImage(restaurantId, image) {
	try {
		if (!restaurantId)
			throw new Error("No restaurant ID has been provided.");

		if (!image || !image.name)
			throw new Error("A valid image has not been provided.");

		const publicImageUrl = await uploadImage(restaurantId, image);
		await updateRestaurantImageReference(restaurantId, publicImageUrl);

		return publicImageUrl;
	} catch (error) {
		console.error("Error processing request:", error);
	}
}

async function uploadImage(restaurantId, image) {
	const filePath = `images/${restaurantId}/${image.name}`;
	const newImageRef = ref(storage, filePath);
	await uploadBytesResumable(newImageRef, image);

	return await getDownloadURL(newImageRef);
}

Die Funktion updateRestaurantImageReference() ist bereits für Sie implementiert. Diese Funktion aktualisiert ein vorhandenes Restaurantdokument in Cloud Firestore mit einer aktualisierten Bild-URL.

Funktion zum Hochladen von Bildern prüfen

So überprüfen Sie, ob das Bild wie erwartet hochgeladen wird:

  1. Erstellen Sie einen Commit mit der Commit-Nachricht „Nutzer dürfen das Foto jedes Restaurants ändern“ und übertragen Sie ihn in Ihr GitHub-Repository.
  2. Öffnen Sie in der Firebase Console die Seite App Hosting und warten Sie, bis die neue Einführung abgeschlossen ist.
  3. Prüfen Sie in der Web-App, ob Sie angemeldet sind, und wählen Sie ein Restaurant aus.
  4. Klicken Sie auf 7067eb41fea41ff0.png und laden Sie ein Bild aus Ihrem Dateisystem hoch. Das Image verlässt Ihre lokale Umgebung und wird in Cloud Storage hochgeladen. Das Bild wird sofort nach dem Hochladen angezeigt.
  5. Rufen Sie Cloud Storage for Firebase auf.
  6. Rufen Sie den Ordner auf, der das Restaurant darstellt. Das hochgeladene Bild ist im Ordner vorhanden.

6cf3f9e2303c931c.png

10. Restaurantbewertungen mit generativer KI zusammenfassen

In diesem Abschnitt fügen Sie eine Funktion für Rezensionszusammenfassungen hinzu, damit Nutzer schnell sehen können, was andere von einem Restaurant halten, ohne jede Rezension lesen zu müssen.

Gemini API-Schlüssel in Cloud Secret Manager speichern

  1. Zur Verwendung der Gemini API benötigen Sie einen API-Schlüssel. Schlüssel in Google AI Studio erstellen
  2. App Hosting lässt sich in Cloud Secret Manager integrieren, damit Sie vertrauliche Werte wie API-Schlüssel sicher speichern können:
    1. Führen Sie in einem Terminal den Befehl aus, um ein neues Secret zu erstellen:
    firebase apphosting:secrets:set gemini-api-key
    
    1. Wenn Sie zur Eingabe des Secret-Werts aufgefordert werden, kopieren Sie den Gemini API-Schlüssel aus Google AI Studio und fügen Sie ihn ein.
    2. Wenn Sie gefragt werden, ob das neue Secret zu apphosting.yaml hinzugefügt werden soll, geben Sie Y ein, um zu bestätigen.

Ihr Gemini API-Schlüssel wird jetzt sicher in Cloud Secret Manager gespeichert und ist für Ihr App Hosting-Backend zugänglich.

Komponente „Rezensionszusammenfassung“ implementieren

  1. Ersetzen Sie in src/components/Reviews/ReviewSummary.jsx die Funktion GeminiSummary durch den folgenden Code:
    export async function GeminiSummary({ restaurantId }) {
        const { firebaseServerApp } = await getAuthenticatedAppForUser();
        const reviews = await getReviewsByRestaurantId(
            getFirestore(firebaseServerApp),
            restaurantId
        );
    
        const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
        const model = genAI.getGenerativeModel({ model: "gemini-pro"});
    
        const reviewSeparator = "@";
        const prompt = `
            Based on the following restaurant reviews, 
            where each review is separated by a '${reviewSeparator}' character, 
            create a one-sentence summary of what people think of the restaurant. 
    
            Here are the reviews: ${reviews.map(review => review.text).join(reviewSeparator)}
        `;
    
        try {
            const result = await model.generateContent(prompt);
            const response = await result.response;
            const text = response.text();
    
            return (
                <div className="restaurant__review_summary">
                    <p>{text}</p>
                    <p> Summarized with Gemini</p>
                </div>
            );
        } catch (e) {
            console.error(e);
            return <p>Error contacting Gemini</p>;
        }
    }
    
  2. Erstellen Sie einen Commit mit der Commit-Nachricht „Use AI to summarize reviews“ und übertragen Sie ihn in Ihr GitHub-Repository.
  3. Öffnen Sie in der Firebase Console die Seite App Hosting und warten Sie, bis die neue Einführung abgeschlossen ist.
  4. Öffnen Sie eine Seite für ein Restaurant. Oben sollten Sie eine Zusammenfassung aller Rezensionen auf der Seite in einem Satz sehen.
  5. Fügen Sie eine neue Rezension hinzu und aktualisieren Sie die Seite. Die Zusammenfassung sollte sich ändern.

11. Fazit

Glückwunsch! Sie haben gelernt, wie Sie mit Firebase einer Next.js-App Funktionen hinzufügen. Dazu haben Sie Folgendes verwendet:

Weitere Informationen