Integracja Firebase z aplikacją Next.js

1. Zanim zaczniesz

Z tego samouczka dowiesz się, jak zintegrować Firebase z aplikacją internetową Next.js o nazwie Friendly Eats, która jest witryną z opiniami o restauracjach.

Aplikacja internetowa Friendly Eats

Gotowa aplikacja internetowa oferuje przydatne funkcje, które pokazują, jak Firebase może pomóc w tworzeniu aplikacji Next.js. Są to:

  • Automatyczne kompilowanie i wdrażanie: w tym laboratorium wykorzystujemy Hosting aplikacji Firebase do automatycznego kompilowania i wdrażania kodu Next.js za każdym razem, gdy przenosisz zmiany do skonfigurowanej gałęzi.
  • Logowanie i wylogowywanie: ukończona aplikacja internetowa umożliwia logowanie się przez Google i wylogowywanie. Logowanie użytkowników i utrzymywanie sesji jest w całości zarządzane przez Uwierzytelnianie Firebase.
  • Obrazy: ukończona aplikacja internetowa umożliwia zalogowanym użytkownikom przesyłanie zdjęć restauracji. Pliki z obrazami są przechowywane w Cloud Storage dla Firebase. Pakiet Firebase JavaScript SDK udostępnia publiczny adres URL przesłanych obrazów. Ten publiczny adres URL jest następnie przechowywany w odpowiednim dokumencie restauracji w Cloud Firestore.
  • Opinie: ukończona aplikacja internetowa umożliwia zalogowanym użytkownikom publikowanie opinii o restauracjach, które składają się z oceny w postaci gwiazdek i wiadomości tekstowej. Informacje o opiniach są przechowywane w Cloud Firestore.
  • Filtry: ukończona aplikacja internetowa umożliwia zalogowanym użytkownikom filtrowanie listy restauracji na podstawie kategorii, lokalizacji i ceny. Możesz też dostosować używaną metodę sortowania. Dostęp do danych jest uzyskiwany z Cloud Firestore, a zapytania Firestore są stosowane na podstawie użytych filtrów.

Wymagania wstępne

  • konto GitHub,
  • Znajomość Next.js i JavaScriptu

Czego się nauczysz

  • Jak używać Firebase z routerem aplikacji Next.js i renderowaniem po stronie serwera.
  • Jak przechowywać obrazy w Cloud Storage dla Firebase.
  • Jak odczytywać i zapisywać dane w bazie danych Cloud Firestore.
  • Jak korzystać z funkcji Zaloguj się przez Google w pakiecie Firebase JavaScript SDK.

Czego potrzebujesz

  • Git
  • Najnowsza stabilna wersja Node.js
  • wybraną przeglądarkę, np. Google Chrome;
  • Środowisko programistyczne z edytorem kodu i terminalem
  • konto Google do tworzenia projektu Firebase i zarządzania nim;
  • możliwość przejścia na abonament Blaze w projekcie Firebase;

2. Konfigurowanie środowiska programistycznego i repozytorium GitHub

W tym Codelabie znajdziesz początkowy kod aplikacji, który korzysta z interfejsu wiersza poleceń Firebase.

Tworzenie repozytorium GitHub

Kod źródłowy ćwiczeń z programowania znajdziesz na stronie https://github.com/firebase/friendlyeats-web. Repozytorium zawiera przykładowe projekty na różne platformy. W tym laboratorium używamy jednak tylko katalogu nextjs-start. Zwróć uwagę na te katalogi:

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

Skopiuj folder nextjs-start do własnego repozytorium:

  1. W terminalu utwórz nowy folder na komputerze i przejdź do nowego katalogu:
    mkdir codelab-friendlyeats-web
    
    cd codelab-friendlyeats-web
    
  2. Użyj pakietu npm giget, aby pobrać tylko folder nextjs-start:
    npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
    
  3. Śledź zmiany lokalnie za pomocą Gita:
    git init
    
    git add .
    
    git commit -m "codelab starting point"
    
    git branch -M main
    
  4. Utwórz nowe repozytorium GitHub: https://github.com/new. Nadaj mu dowolną nazwę.
  5. Skopiuj nowy adres URL utworzony przez GitHub. Będzie on wyglądać mniej więcej tak:
    • https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git lub
    • git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
  6. Wypchnij lokalne zmiany do nowego repozytorium GitHub, wykonując to polecenie. Zastąp symbol zastępczy <REPOSITORY_URL> rzeczywistym adresem URL repozytorium.
    git remote add origin <REPOSITORY_URL>
    
    git push -u origin main
    
  7. W repozytorium GitHub powinien pojawić się kod początkowy.

Instalowanie lub aktualizowanie wiersza poleceń Firebase

Uruchom to polecenie, aby sprawdzić, czy wiersz poleceń Firebase jest zainstalowany i czy ma wersję 14.1.0 lub nowszą:

firebase --version

Jeśli widzisz starszą wersję lub nie masz zainstalowanego wiersza poleceń Firebase, uruchom polecenie instalacji:

npm install -g firebase-tools@latest

Jeśli nie możesz zainstalować wiersza poleceń Firebase z powodu błędów uprawnień, zapoznaj się z dokumentacją npm lub skorzystaj z innej opcji instalacji.

Logowanie w Firebase

  1. Aby zalogować się w interfejsie wiersza poleceń Firebase, uruchom to polecenie:
    firebase login
    
  2. Wpisz Y lub N w zależności od tego, czy chcesz, aby Firebase zbierał dane.
  3. W przeglądarce wybierz konto Google, a potem kliknij Zezwól.

3. Konfigurowanie projektu Firebase

W tej sekcji skonfigurujesz projekt Firebase i powiążesz z nim aplikację internetową Firebase. Skonfigurujesz też usługi Firebase używane przez przykładową aplikację internetową.

Tworzenie projektu Firebase

  1. Zaloguj się w konsoli Firebase za pomocą tego samego konta Google, którego używasz w poprzednim kroku.
  2. Kliknij przycisk, aby utworzyć nowy projekt, a potem wpisz jego nazwę (np. FriendlyEats Codelab).
  3. Kliknij Dalej.
  4. Po wyświetleniu monitu przeczytaj i zaakceptuj warunki usługi Firebase, a potem kliknij Dalej.
  5. (Opcjonalnie) Włącz w konsoli Firebase pomoc AI (nazywaną „Gemini w Firebase”).
  6. W tym samouczku nie potrzebujesz Google Analytics, więc wyłącz opcję Google Analytics.
  7. Kliknij Utwórz projekt, poczekaj, aż projekt zostanie udostępniony, a następnie kliknij Dalej.

Przejście na wyższy abonament Firebase

Aby korzystać z Hostingu aplikacji Firebase i Cloud Storage for Firebase, Twój projekt Firebase musi być objęty abonamentem Blaze (płatność według wykorzystania), co oznacza, że jest połączony z kontem rozliczeniowym Cloud.

  • Konto rozliczeniowe Cloud wymaga formy płatności, np. karty kredytowej.
  • Jeśli dopiero zaczynasz korzystać z Firebase i Google Cloud, sprawdź, czy możesz otrzymać środki w wysokości 300 USD i bezpłatne konto rozliczeniowe Cloud.
  • Jeśli wykonujesz te ćwiczenia w ramach wydarzenia, zapytaj organizatora, czy są dostępne środki w Google Cloud.

Aby przenieść projekt na abonament Blaze:

  1. W konsoli Firebase wybierz przejście na wyższy abonament.
  2. Wybierz pakiet Blaze. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie, aby połączyć konto rozliczeniowe Cloud z projektem.
    Jeśli w ramach tego przejścia na wyższy abonament konieczne było utworzenie konta rozliczeniowego Cloud, może być konieczne powrócenie do procesu przejścia na wyższy abonament w konsoli Firebase, aby go dokończyć.

Dodawanie aplikacji internetowej do projektu Firebase

  1. Otwórz Przegląd projektu w projekcie Firebase, a potem kliknij e41f2efdd9539c31.png Internet.

    Jeśli w projekcie masz już zarejestrowane aplikacje, kliknij Dodaj aplikację, aby zobaczyć ikonę Internet.
  2. W polu tekstowym Pseudonim aplikacji wpisz łatwy do zapamiętania pseudonim aplikacji, np. My Next.js app.
  3. Pole wyboru Skonfiguruj też Hosting Firebase dla tej aplikacji pozostaw niezaznaczone.
  4. Kliknij Zarejestruj aplikację > Przejdź do konsoli.

Konfigurowanie usług Firebase w konsoli Firebase

Konfigurowanie uwierzytelniania

  1. W konsoli Firebase otwórz Uwierzytelnianie.
  2. Kliknij Rozpocznij.
  3. W kolumnie Dodatkowi dostawcy kliknij Google > Włącz.
  4. W polu tekstowym Nazwa projektu widoczna publicznie wpisz łatwą do zapamiętania nazwę, np. My Next.js app.
  5. W menu Adres e-mail pomocy dotyczący projektu wybierz swój adres e-mail.
  6. Kliknij Zapisz.

Konfigurowanie Cloud Firestore

  1. W panelu po lewej stronie konsoli Firebase rozwiń Kompilacja, a następnie wybierz Baza danych Firestore.
  2. Kliknij Utwórz bazę danych.
  3. W polu Identyfikator bazy danych pozostaw wartość (default).
  4. Wybierz lokalizację bazy danych i kliknij Dalej.
    W przypadku prawdziwej aplikacji wybierz lokalizację, która jest blisko użytkowników.
  5. Kliknij Uruchom w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł bezpieczeństwa.
    W dalszej części tego laboratorium dodasz reguły bezpieczeństwa, aby zabezpieczyć swoje dane. Nierozpowszechniajani nie udostępniaj publicznie aplikacji bez dodania reguł bezpieczeństwa do bazy danych.
  6. Kliknij Utwórz.

Konfigurowanie Cloud Storage dla Firebase

  1. W panelu po lewej stronie konsoli Firebase rozwiń Kompilacja, a następnie wybierz Storage.
  2. Kliknij Rozpocznij.
  3. Wybierz lokalizację domyślnego zasobnika Storage.
    Zasobniki w regionach US-WEST1, US-CENTRAL1 i US-EAST1 mogą korzystać z poziomu „Zawsze bezpłatny” w Google Cloud Storage. W przypadku zasobników w innych lokalizacjach obowiązuje cennik i wykorzystanie Google Cloud Storage.
  4. Kliknij Uruchom w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł bezpieczeństwa.
    W dalszej części tego laboratorium dodasz reguły bezpieczeństwa, aby zabezpieczyć swoje dane. Nieudostępniaj aplikacji publicznie bez dodania reguł bezpieczeństwa do zasobnika Storage.
  5. Kliknij Utwórz.

Wdrażanie reguł zabezpieczeń

Kod zawiera już zestawy reguł zabezpieczeń dla Firestore i Cloud Storage dla Firebase. Po wdrożeniu reguł bezpieczeństwa dane w bazie danych i w zasobniku są lepiej chronione przed niewłaściwym użyciem.

  1. W terminalu skonfiguruj interfejs CLI do korzystania z utworzonego wcześniej projektu Firebase:
    firebase use --add
    
    Gdy pojawi się prośba o podanie aliasu, wpisz friendlyeats-codelab.
  2. Aby wdrożyć te reguły zabezpieczeń (a także indeksy, które będą potrzebne później), uruchom w terminalu to polecenie:
    firebase deploy --only firestore,storage
    
  3. Jeśli pojawi się pytanie: "Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?", naciśnij Enter, aby wybrać Tak.

4. Sprawdź początkową bazę kodu

W tej sekcji zapoznasz się z kilkoma obszarami początkowej bazy kodu aplikacji, do których dodasz funkcje w tym laboratorium.

Struktura folderów i plików

Poniższa tabela zawiera omówienie struktury folderów i plików aplikacji:

Foldery i pliki

Opis

src/components

Komponenty React do filtrów, nagłówków, szczegółów restauracji i opinii

src/lib

funkcje narzędziowe, które nie są koniecznie powiązane z Reactem ani Next.js;

src/lib/firebase

Kod specyficzny dla Firebase i konfiguracja Firebase

public

statyczne zasoby w aplikacji internetowej, takie jak ikony;

src/app

Routing za pomocą routera aplikacji Next.js

package.json i package-lock.json

Zależności projektu w npm

next.config.js

Konfiguracja specyficzna dla Next.js (działania serwera są włączone)

jsconfig.json

Konfiguracja usługi językowej JavaScript

Komponenty serwera i klienta

Aplikacja to aplikacja internetowa Next.js, która korzysta z routera aplikacji. Renderowanie po stronie serwera jest używane w całej aplikacji. Na przykład plik src/app/page.js to komponent serwera odpowiedzialny za stronę główną. Plik src/components/RestaurantListings.jsx to komponent klienta oznaczony dyrektywą "use client" na początku pliku.

Importowanie wyciągów

Możesz zauważyć instrukcje importu podobne do tych:

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

Aplikacja używa symbolu @, aby uniknąć nieporęcznych względnych ścieżek importu. Jest to możliwe dzięki aliasom ścieżek.

Interfejsy API Firebase

Cały kod interfejsu Firebase API jest zawarty w katalogu src/lib/firebase. Poszczególne komponenty Reacta importują następnie opakowane funkcje z katalogu src/lib/firebase zamiast importować funkcje Firebase bezpośrednio.

Dane testowe

Przykładowe dane restauracji i opinii znajdują się w pliku src/lib/randomData.js. Dane z tego pliku są zbierane w kodzie w pliku src/lib/fakeRestaurants.js.

5. Tworzenie backendu hostingu aplikacji

W tej sekcji skonfigurujesz backend App Hosting, aby obserwować gałąź w repozytorium Git.

Po przeczytaniu tej sekcji będziesz mieć backend App Hosting połączony z repozytorium w GitHubie, który będzie automatycznie ponownie kompilować i wdrażać nową wersję aplikacji za każdym razem, gdy przeniesiesz nowe zatwierdzenie do gałęzi main.

Utworzenie backendu

  1. Otwórz stronę hostingu aplikacji w konsoli Firebase:

Stan zerowy konsoli App Hosting z przyciskiem „Rozpocznij”

  1. Aby rozpocząć proces tworzenia backendu, kliknij „Rozpocznij”. Skonfiguruj backend w ten sposób:
  2. Wybierz region. W przypadku prawdziwej aplikacji wybierz region najbliżej użytkowników.
  3. Postępuj zgodnie z instrukcjami w kroku „Importowanie repozytorium GitHub”, aby połączyć utworzone wcześniej repozytorium GitHub.
  4. Ustawienia wdrażania:
    1. Pozostaw katalog główny jako /
    2. Ustaw gałąź na żywo na main
    3. Włącz automatyczne wdrażanie
  5. Nazwij backend friendlyeats-codelab.
  6. W sekcji „Powiąż aplikację internetową Firebase” kliknij „Utwórz nową aplikację internetową Firebase”.
  7. Kliknij „Zakończ i wdroż”. Po chwili przejdziesz na nową stronę, na której zobaczysz stan nowego backendu hostingu aplikacji.
  8. Po zakończeniu wdrażania kliknij bezpłatną domenę w sekcji „Domeny”. Zanim zacznie działać, może minąć kilka minut ze względu na propagację DNS.
  9. Ojej. Po załadowaniu strony zobaczysz komunikat o błędzie „Błąd aplikacji: wystąpił wyjątek po stronie serwera (więcej informacji znajdziesz w logach serwera)”.
  10. W konsoli Firebase sprawdź kartę „Dzienniki” zaplecza hostingu aplikacji. Wyświetli się dziennik „Błąd: nie zaimplementowano”. Naprawimy to w następnym kroku, gdy dodamy uwierzytelnianie.

Udało Ci się wdrożyć początkową aplikację internetową. Za każdym razem, gdy przeniesiesz nowe zatwierdzenie do gałęzi main w repozytorium GitHub, w konsoli Firebase zobaczysz nową kompilację i rozpocznie się wdrażanie. Po zakończeniu wdrażania Twoja witryna zostanie automatycznie zaktualizowana.

6. Dodawanie uwierzytelniania do aplikacji internetowej

W tej sekcji dodasz do aplikacji internetowej uwierzytelnianie, aby można było się do niej zalogować.

Dodaj autoryzowaną domenę

Usługa Uwierzytelnianie Firebase będzie akceptować prośby o zalogowanie tylko z dozwolonych domen. Dodamy tu domenę backendu hostingu aplikacji do listy zatwierdzonych domen w Twoim projekcie.

  1. Skopiuj domenę backendu hostingu aplikacji ze strony „Przegląd” hostingu aplikacji.
  2. Otwórz kartę Ustawienia uwierzytelniania i wybierz Autoryzowane domeny.
  3. Kliknij przycisk Dodaj domenę.
  4. Wpisz domenę backendu hostingu aplikacji.
  5. Kliknij Dodaj.

Wdrażanie funkcji logowania i wylogowywania

  1. W pliku src/lib/firebase/auth.js zastąp funkcje onAuthStateChanged, onIdTokenChanged, signInWithGoogle i signOut tym kodem:
export function onAuthStateChanged(cb) {
  return _onAuthStateChanged(auth, cb);
}

export function onIdTokenChanged(cb) {
  return _onIdTokenChanged(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);
  }
}

Ten kod korzysta z tych interfejsów API Firebase:

Firebase API

Opis

auth.onAuthStateChanged

Dodaje obserwatora zmian stanu logowania użytkownika.

auth.onIdTokenChanged

Dodaje obserwatora zmian tokena identyfikacyjnego użytkownika.

GoogleAuthProvider

Tworzy instancję dostawcy uwierzytelniania Google.

signInWithPopup

Rozpoczyna proces uwierzytelniania oparty na oknie dialogowym.

auth.signOut

Wylogowuje użytkownika.

W pliku src/components/Header.jsx kod wywołuje już funkcje signInWithGooglesignOut.

Wysyłanie stanu uwierzytelniania na serwer

Aby przekazać stan uwierzytelniania na serwer, użyjemy plików cookie. Gdy stan uwierzytelniania w kliencie ulegnie zmianie, zaktualizujemy plik cookie __session.

W pliku src/components/Header.jsx zastąp funkcję useUserSession tym kodem:

function useUserSession(initialUser) {
  useEffect(() => {
    return onIdTokenChanged(async (user) => {
      if (user) {
        const idToken = await user.getIdToken();
        await setCookie("__session", idToken);
      } else {
        await deleteCookie("__session");
      }
      if (initialUser?.uid === user?.uid) {
        return;
      }
      window.location.reload();
    });
  }, [initialUser]);

  return initialUser;
}

Odczytywanie stanu uwierzytelniania na serwerze

Użyjemy FirebaseServerApp, aby odzwierciedlić stan uwierzytelniania klienta na serwerze.

Otwórz src/lib/firebase/serverApp.js i zastąp funkcję getAuthenticatedAppForUser:

export async function getAuthenticatedAppForUser() {
  const authIdToken = (await cookies()).get("__session")?.value;

  // Firebase Server App is a new feature in the JS SDK that allows you to
  // instantiate the SDK with credentials retrieved from the client & has
  // other affordances for use in server environments.
  const firebaseServerApp = initializeServerApp(
    // https://github.com/firebase/firebase-js-sdk/issues/8863#issuecomment-2751401913
    initializeApp(),
    {
      authIdToken,
    }
  );

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

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

Weryfikowanie zmian

Układ główny w pliku src/app/layout.js renderuje nagłówek i przekazuje użytkownika (jeśli jest dostępny) jako właściwość.

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

Oznacza to, że komponent <Header> renderuje dane użytkownika (jeśli są dostępne) w czasie działania serwera. Jeśli w trakcie cyklu życia strony po jej początkowym wczytaniu nastąpią jakiekolwiek aktualizacje uwierzytelniania, obsłuży je funkcja onAuthStateChanged.

Teraz nadszedł czas na wdrożenie nowej wersji i sprawdzenie, co zostało utworzone.

  1. Utwórz zatwierdzenie z komunikatem „Add authentication” (Dodaj uwierzytelnianie) i prześlij je do repozytorium GitHub.
  2. Otwórz stronę hostingu aplikacji w konsoli Firebase i poczekaj, aż nowe wdrożenie się zakończy.
  3. Sprawdź nowe zachowanie uwierzytelniania:
    1. Odśwież aplikację internetową w przeglądarce. W nagłówku pojawi się Twoja nazwa wyświetlana.
    2. Wyloguj się i zaloguj jeszcze raz. Możesz powtórzyć ten krok w przypadku innych użytkowników.
    3. Opcjonalnie: kliknij prawym przyciskiem myszy aplikację internetową, wybierz Wyświetl źródło strony i wyszukaj wyświetlaną nazwę. Pojawia się w surowym kodzie HTML zwróconym z serwera.

7. Wyświetlanie informacji o restauracji

Aplikacja internetowa zawiera przykładowe dane dotyczące restauracji i opinii.

Dodawanie co najmniej 1 restauracji

Aby wstawić przykładowe dane restauracji do lokalnej bazy danych Cloud Firestore, wykonaj te czynności:

  1. Zaloguj się w aplikacji internetowej, jeśli jeszcze tego nie zrobiono. Następnie kliknij 2cf67d488d8e6332.png > Dodaj przykładowe restauracje.
  2. W konsoli Firebase na stronie Baza danych Firestore kliknij restaurants. Widzisz dokumenty najwyższego poziomu documents w kolekcji restauracji, z których każdy reprezentuje jedną restaurację.
  3. Kliknij kilka dokumentów, aby poznać właściwości dokumentu restauracji.

Wyświetlanie listy restauracji

W bazie danych Cloud Firestore znajdują się teraz restauracje, które aplikacja internetowa Next.js może wyświetlać.

Aby zdefiniować kod pobierania danych:

  1. W pliku src/app/page.js znajdź komponent serwera <Home /> i sprawdź wywołanie funkcji getRestaurants, która pobiera listę restauracji w czasie działania serwera. Funkcję getRestaurants wdrożysz w tych krokach.
  2. W pliku src/lib/firebase/firestore.js zastąp funkcje applyQueryFiltersgetRestaurants tym kodem:
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. Utwórz zatwierdzenie z komunikatem „Read the list of restaurants from Firestore” (Odczytaj listę restauracji z Firestore) i prześlij je do repozytorium GitHub.
  2. Otwórz stronę hostingu aplikacji w konsoli Firebase i poczekaj, aż nowe wdrożenie się zakończy.
  3. W aplikacji internetowej odśwież stronę. Zdjęcia restauracji pojawiają się na stronie w postaci kafelków.

Sprawdź, czy informacje o restauracjach wczytują się w czasie działania serwera.

W przypadku korzystania z platformy Next.js może nie być oczywiste, kiedy dane są wczytywane w czasie działania serwera lub klienta.

Aby sprawdzić, czy wizytówki restauracji wczytują się w czasie działania serwera, wykonaj te czynności:

  1. W aplikacji internetowej otwórz Narzędzia deweloperskie i wyłącz JavaScript.

Wyłączanie JavaScriptu w Narzędziach deweloperskich

  1. Odśwież aplikację internetową. Listy restauracji nadal się wczytują. Informacje o restauracji są zwracane w odpowiedzi serwera. Gdy JavaScript jest włączony, informacje o restauracji są wypełniane za pomocą kodu JavaScript po stronie klienta.
  2. W Narzędziach deweloperskich ponownie włącz JavaScript.

Nasłuchiwanie aktualizacji restauracji za pomocą detektorów zrzutów Cloud Firestore

W poprzedniej sekcji pokazaliśmy, jak początkowy zestaw restauracji został wczytany z pliku src/app/page.js. Plik src/app/page.js jest komponentem serwera i jest renderowany na serwerze, w tym kod pobierania danych Firebase.

Plik src/components/RestaurantListings.jsx jest komponentem klienta i można go skonfigurować tak, aby uzupełniał znaczniki renderowane na serwerze.

Aby skonfigurować plik src/components/RestaurantListings.jsx do wypełniania znaczników renderowanych po stronie serwera, wykonaj te czynności:

  1. W pliku src/components/RestaurantListings.jsx zwróć uwagę na ten kod, który jest już napisany:
useEffect(() => {
    return getRestaurantsSnapshot((data) => {
      setRestaurants(data);
    }, filters);
  }, [filters]);

Ten kod wywołuje funkcję getRestaurantsSnapshot(), która jest podobna do funkcji getRestaurants() zaimplementowanej w poprzednim kroku. Ta funkcja zrzutu udostępnia jednak mechanizm wywołania zwrotnego, dzięki czemu wywołanie zwrotne jest wywoływane za każdym razem, gdy w kolekcji restauracji wprowadzana jest zmiana.

  1. W pliku src/lib/firebase/firestore.js zastąp funkcję getRestaurantsSnapshot() tym kodem:
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);

  return 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);
  });
}

Zmiany wprowadzone na stronie Baza danych Firestore są teraz odzwierciedlane w aplikacji internetowej w czasie rzeczywistym.

  1. Utwórz zatwierdzenie z komunikatem „Listen for realtime restaurant updates” (Nasłuchiwanie aktualizacji restauracji w czasie rzeczywistym) i prześlij je do repozytorium GitHub.
  2. Otwórz stronę hostingu aplikacji w konsoli Firebase i poczekaj, aż nowe wdrożenie się zakończy.
  3. W aplikacji internetowej kliknij 27ca5d1e8ed8adfe.png > Dodaj przykładowe restauracje. Jeśli funkcja migawki jest prawidłowo wdrożona, restauracje będą się pojawiać w czasie rzeczywistym bez odświeżania strony.

8. Zapisywanie opinii przesłanych przez użytkowników z aplikacji internetowej

  1. W pliku src/lib/firebase/firestore.js zastąp funkcję updateWithRating() tym kodem:
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()),
  });
};

Ten kod wstawia nowy dokument Firestore reprezentujący nową opinię. Kod aktualizuje też istniejący dokument Firestore, który reprezentuje restaurację, o zaktualizowane dane dotyczące liczby ocen i średniej obliczonej oceny.

  1. Zastąp funkcję addReviewToRestaurant() tym kodem:
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;
	}
}

Implementowanie działania serwera Next.js

Działanie serwera Next.js udostępnia wygodny interfejs API do uzyskiwania dostępu do danych formularza, np. data.get("text"), aby pobrać wartość tekstową z ładunku przesłanego formularza.

Aby przetworzyć przesłany formularz opinii za pomocą działania serwera Next.js, wykonaj te czynności:

  1. W pliku src/components/ReviewDialog.jsx znajdź atrybut action w elemencie <form>.
<form action={handleReviewFormSubmission}>

Wartość atrybutu action odnosi się do funkcji, którą zaimplementujesz w następnym kroku.

  1. W pliku src/app/actions.js zastąp funkcję handleReviewFormSubmission() tym kodem:
// 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"),
        });
}

Dodawanie opinii o restauracji

Wdrożono obsługę przesyłania opinii, więc teraz możesz sprawdzić, czy opinie są prawidłowo wstawiane do Cloud Firestore.

Aby dodać opinię i sprawdzić, czy została wstawiona do Cloud Firestore, wykonaj te czynności:

  1. Utwórz zatwierdzenie z komunikatem „Allow users to submit restaurant reviews” (Zezwól użytkownikom na przesyłanie opinii o restauracjach) i prześlij je do repozytorium GitHub.
  2. Otwórz stronę hostingu aplikacji w konsoli Firebase i poczekaj, aż nowe wdrożenie się zakończy.
  3. Odśwież aplikację internetową i wybierz restaurację na stronie głównej.
  4. Na stronie restauracji kliknij 3e19beef78bb0d0e.png.
  5. Wybierz liczbę gwiazdek.
  6. Napisz opinię.
  7. Kliknij Prześlij. Twoja opinia pojawi się u góry listy opinii.
  8. W Cloud Firestore w panelu Dodaj dokument wyszukaj i wybierz dokument restauracji, którą oceniasz.
  9. W panelu Rozpocznij zbieranie kliknij oceny.
  10. W panelu Dodaj dokument znajdź dokument do sprawdzenia, aby upewnić się, że został wstawiony zgodnie z oczekiwaniami.

Dokumenty w emulatorze Firestore

9. Zapisywanie plików przesłanych przez użytkowników z aplikacji internetowej

W tej sekcji dodasz funkcję, która umożliwi zastąpienie obrazu powiązanego z restauracją po zalogowaniu się. Prześlij obraz do Firebase Storage i zaktualizuj adres URL obrazu w dokumencie Cloud Firestore, który reprezentuje restaurację.

Aby zapisać pliki przesłane przez użytkowników z aplikacji internetowej, wykonaj te czynności:

  1. W pliku src/components/Restaurant.jsx sprawdź kod, który jest uruchamiany, gdy użytkownik przesyła plik:
async function handleRestaurantImage(target) {
  const image = target.files ? target.files[0] : null;
  if (!image) {
    return;
  }

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

Nie musisz wprowadzać w tej funkcji żadnych zmian, ale w kolejnych krokach zaimplementujesz działanie funkcji updateRestaurantImage().

  1. W pliku src/lib/firebase/storage.js zastąp funkcje updateRestaurantImage()uploadImage() tym kodem:
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);
}

Funkcja updateRestaurantImageReference() jest już wdrożona. Ta funkcja aktualizuje istniejący dokument restauracji w Cloud Firestore, dodając do niego zaktualizowany adres URL obrazu.

Sprawdź funkcję przesyłania obrazów.

Aby sprawdzić, czy obraz przesyła się zgodnie z oczekiwaniami, wykonaj te czynności:

  1. Utwórz zatwierdzenie z komunikatem „Allow users to change each restaurants' photo” (Zezwól użytkownikom na zmianę zdjęcia każdej restauracji) i prześlij je do repozytorium GitHub.
  2. Otwórz stronę hostingu aplikacji w konsoli Firebase i poczekaj, aż nowe wdrożenie się zakończy.
  3. W aplikacji internetowej sprawdź, czy jesteś zalogowany(-a), i wybierz restaurację.
  4. Kliknij 7067eb41fea41ff0.png i prześlij obraz z systemu plików. Obraz opuszcza środowisko lokalne i jest przesyłany do Cloud Storage. Obraz pojawi się natychmiast po przesłaniu.
  5. Otwórz Cloud Storage dla Firebase.
  6. Otwórz folder reprezentujący restaurację. Przesłany obraz znajduje się w folderze.

6cf3f9e2303c931c.png

10. Podsumowywanie opinii o restauracjach za pomocą generatywnej AI

W tej sekcji dodasz funkcję podsumowania opinii, dzięki której użytkownik będzie mógł szybko sprawdzić, co myślą o restauracji inni, bez konieczności czytania każdej opinii.

Przechowywanie klucza interfejsu Gemini API w usłudze Cloud Secret Manager

  1. Aby korzystać z interfejsu Gemini API, musisz mieć klucz interfejsu API. Otwórz Google AI Studio i kliknij „Utwórz klucz interfejsu API”.
  2. W polu „Wyszukaj projekty Google Cloud” wybierz projekt Firebase. Każdy projekt Firebase jest oparty na projekcie Google Cloud.
  3. App Hosting jest zintegrowany z Cloud Secret Manager, co umożliwia bezpieczne przechowywanie wartości wrażliwych, takich jak klucze interfejsu API:
    1. W terminalu uruchom polecenie, aby utworzyć nowy obiekt tajny:
    firebase apphosting:secrets:set GEMINI_API_KEY
    
    1. Gdy pojawi się prośba o podanie wartości tajnej, skopiuj i wklej klucz interfejsu Gemini API z Google AI Studio.
    2. Gdy pojawi się pytanie, czy nowy klucz tajny jest przeznaczony do środowiska produkcyjnego czy testów lokalnych, wybierz „Środowisko produkcyjne”.
    3. Gdy pojawi się pytanie, czy chcesz przyznać dostęp, aby konto usługi backendu mogło uzyskać dostęp do klucza tajnego, wybierz „Tak”.
    4. Gdy pojawi się pytanie, czy nowy klucz tajny ma zostać dodany do apphosting.yaml, wpisz Y, aby zaakceptować.

Klucz interfejsu Gemini API jest teraz bezpiecznie przechowywany w usłudze Cloud Secret Manager i jest dostępny dla backendu App Hosting.

Wdrażanie komponentu podsumowania opinii

  1. W pliku src/components/Reviews/ReviewSummary.jsx zastąp funkcję GeminiSummary tym kodem:
    export async function GeminiSummary({ restaurantId }) {
      const { firebaseServerApp } = await getAuthenticatedAppForUser();
      const reviews = await getReviewsByRestaurantId(
        getFirestore(firebaseServerApp),
        restaurantId
      );
    
      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 {
        if (!process.env.GEMINI_API_KEY) {
          // Make sure GEMINI_API_KEY environment variable is set:
          // https://firebase.google.com/docs/genkit/get-started
          throw new Error(
            'GEMINI_API_KEY not set. Set it with "firebase apphosting:secrets:set GEMINI_API_KEY"'
          );
        }
    
        // Configure a Genkit instance.
        const ai = genkit({
          plugins: [googleAI()],
          model: gemini20Flash, // set default model
        });
        const { text } = await ai.generate(prompt);
    
        return (
          <div className="restaurant__review_summary">
            <p>{text}</p>
            <p> Summarized with Gemini</p>
          </div>
        );
      } catch (e) {
        console.error(e);
        return <p>Error summarizing reviews.</p>;
      }
    }
    
  2. Utwórz zatwierdzenie z komunikatem „Use AI to summarize reviews” (Użyj AI do podsumowywania opinii) i prześlij je do repozytorium GitHub.
  3. Otwórz stronę hostingu aplikacji w konsoli Firebase i poczekaj, aż nowe wdrożenie się zakończy.
  4. Otwórz stronę restauracji. U góry powinna być widoczna podsumowująca wszystkie opinie na stronie.
  5. Dodaj nową opinię i odśwież stronę. Powinno pojawić się podsumowanie zmiany.

11. Podsumowanie

Gratulacje! Dowiedzieliśmy się, jak używać Firebase do dodawania funkcji i funkcjonalności do aplikacji Next.js. W szczególności użyliśmy tych usług:

Więcej informacji