1. Zanim zaczniesz
Z tego Codelab dowiesz się, jak zintegrować Firebase z aplikacją internetową Next.js o nazwie Friendly Eats, która jest stroną z opiniami o restauracjach.
Ukończona aplikacja internetowa zawiera przydatne funkcje, które pokazują, jak Firebase może pomóc Ci w tworzeniu aplikacji Next.js. Funkcje te obejmują:
- Automatyczne kompilowanie i wdrażanie: to ćwiczenie w Codelabs korzysta z Firebase App Hosting do automatycznego kompilowania i wdrażania kodu Next.js za każdym razem, gdy wypchniesz go do skonfigurowanej gałęzi.
- Logowanie się i wylogowywanie: gotowa aplikacja internetowa umożliwia logowanie się przez Google i wylogowywanie. Logowaniem i trwałością użytkowników zarządza się wyłącznie za pomocą Uwierzytelniania Firebase.
- Obrazy: ukończona aplikacja internetowa umożliwia zalogowanym użytkownikom przesyłanie zdjęć restauracji. Zasoby obrazów są przechowywane w Cloud Storage dla Firebase. Pakiet Firebase JavaScript SDK udostępnia publiczny URL przesłanych obrazów. Ten publiczny adres URL jest następnie zapisywany w odpowiednim dokumencie restauracji w Cloud Firestore.
- Opinie: gotowa aplikacja internetowa umożliwia zalogowanym użytkownikom publikowanie opinii o restauracjach, które składają się z oceny w gwiazdkach 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 według kategorii, lokalizacji i ceny. Możesz też dostosować używaną metodę sortowania. Dane są pobierane z Cloud Firestore, a zapytania do 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 zapisywać obrazy w Cloud Storage dla Firebase.
- Jak odczytywać i zapisywać dane w bazie danych Cloud Firestore.
- Jak korzystać z funkcji logowania przez Google za pomocą pakietu SDK Firebase JavaScript.
Czego potrzebujesz
- Git
- Najnowsza stabilna wersja Node.js
- wybraną przeglądarkę, na przykład 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. Skonfiguruj środowisko programistyczne i repozytorium GitHub
To ćwiczenie w Codelabs wykorzystuje startową bazę kodu aplikacji i opiera się na interfejsie wiersza poleceń Firebase.
Tworzenie repozytorium GitHub
Źródło kodu do ćwiczeń znajdziesz na stronie https://github.com/firebase/friendlyeats-web. Repozytorium zawiera przykładowe projekty na wiele platform. Ten kodlab używa 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 swojego repozytorium:
- Za pomocą terminala utwórz nowy folder na komputerze i przejdź do nowego katalogu:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- Użyj pakietu npm giget, aby pobrać tylko folder
nextjs-start
:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- Śledź zmiany lokalnie za pomocą git:
git init git commit -a -m "codelab starting point" git branch -M main
- Utwórz nowe repozytorium GitHub: https://github.com/new. Możesz nadać mu dowolną nazwę.
- Serwis GitHub wyświetli nowy adres URL repozytorium, który wygląda podobnie do tego:
https://github.com/
lub/ .git git@github.com:
. Skopiuj ten adres URL./ .git
- Serwis GitHub wyświetli nowy adres URL repozytorium, który wygląda podobnie do tego:
- Prześlij lokalne zmiany do nowego repozytorium GitHub. Uruchom to polecenie, zastępując adres URL repozytorium zmienną
.git remote add origin <your-repository-url> git push -u origin main
- Kod startowy powinien pojawić się w Twoim repozytorium GitHub.
Instalowanie lub aktualizowanie interfejsu wiersza poleceń Firebase
Uruchom to polecenie, aby sprawdzić, czy masz zainstalowany interfejs wiersza poleceń Firebase w wersji 13.9.0 lub nowszej:
firebase --version
Jeśli widzisz niższą wersję lub nie masz zainstalowanego interfejsu wiersza poleceń Firebase, uruchom polecenie instalacji:
npm install -g firebase-tools@latest
Jeśli nie możesz zainstalować interfejsu wiersza poleceń Firebase z powodu błędów uprawnień, zapoznaj się z dokumentacją npm lub użyj innej opcji instalacji.
Logowanie się w Firebase
- Aby zalogować się w interfejsie wiersza poleceń Firebase, uruchom to polecenie:
firebase login
- W zależności od tego, czy chcesz, aby Firebase gromadził dane, wpisz
Y
czyN
. - W przeglądarce wybierz swoje konto Google, a następnie kliknij Zezwól.
3. Konfigurowanie projektu Firebase
W tej sekcji skonfigurujesz projekt Firebase i połączysz z nim aplikację internetową Firebase. Skonfigurujesz też usługi Firebase używane przez przykładową aplikację internetową.
Tworzenie projektu Firebase
- W konsoli Firebase kliknij Dodaj projekt.
- W polu tekstowym Wpisz nazwę projektu wpisz
FriendlyEats Codelab
(lub inną nazwę projektu), a potem kliknij Dalej. - W oknie Potwierdź plan płatności Firebase sprawdź, czy wybrany plan to Blaze, a potem kliknij Potwierdź plan.
- Ćwiczenia z programowania nie wymagają Google Analytics, więc wyłącz opcję Włącz Google Analytics dla tego projektu.
- Kliknij Utwórz projekt.
- Poczekaj, aż projekt zostanie przygotowany, a potem kliknij Dalej.
- W projekcie Firebase otwórz Ustawienia projektu. Zapisz identyfikator projektu, bo będzie Ci on potrzebny później. Ten unikalny identyfikator służy do identyfikowania projektu (np. w interfejsie wiersza poleceń Firebase).
Przejdź na wyższy abonament Firebase
Aby korzystać z hostingu aplikacji i Cloud Storage w Firebase, musisz mieć projekt Firebase w abonamentie płatność według wykorzystania (Blaze), co oznacza, że jest on połączony z kontem płatności Cloud.
- Do konta rozliczeniowego Cloud wymagana jest forma płatności, np. karta kredytowa.
- Jeśli dopiero zaczynasz korzystać z Firebase i Google Cloud, sprawdź, czy kwalifikujesz się do otrzymania środków w wysokości 300 USD i bezpłatnego okresu próbnego konta rozliczeniowego Cloud.
- Jeśli wykonujesz to ćwiczenie w ramach wydarzenia, zapytaj organizatora, czy są dostępne jakieś kredyty Cloud.
Aby przenieść projekt na abonament Blaze, wykonaj te czynności:
- W konsoli Firebase wybierz uaktualnienie abonamentu.
- Wybierz abonament Blaze. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie, aby połączyć konto rozliczeniowe Cloud z projektem.
Jeśli w ramach tego uaktualnienia konieczne było utworzenie konta rozliczeniowego Cloud, może być konieczne powrót do procesu uaktualniania w konsoli Firebase.
Dodawanie aplikacji internetowej do projektu Firebase
- W projekcie Firebase otwórz Przegląd projektu i kliknij Sieć.
Jeśli masz już w projekcie zarejestrowane aplikacje, kliknij Dodaj aplikację, żeby wyświetlić ikonę internetu. - W polu tekstowym Pseudonim aplikacji wpisz zapadający w pamięć pseudonim aplikacji, np.
My Next.js app
. - Nie zaznaczaj pola wyboru Skonfiguruj również Hosting Firebase dla tej aplikacji.
- Kliknij Zarejestruj aplikację > Dalej > Dalej > Przejdź do konsoli.
Konfigurowanie usług Firebase w konsoli Firebase
Konfigurowanie uwierzytelniania
- W konsoli Firebase otwórz Uwierzytelnianie.
- Kliknij Rozpocznij.
- W kolumnie Dodatkowi dostawcy kliknij Google > Włącz.
- W polu tekstowym Nazwa projektu widoczna publicznie wpisz zapadającą w pamięć nazwę, np.
My Next.js app
. - W menu Adres e-mail pomocy dla projektu wybierz swój adres e-mail.
- Kliknij Zapisz.
Konfigurowanie Cloud Firestore
- W panelu po lewej stronie w konsoli Firebase rozwiń Kompilacja, a potem wybierz Baza danych Firestore.
- Kliknij Utwórz bazę danych.
- W polu Identyfikator bazy danych pozostaw wartość
(default)
. - Wybierz lokalizację bazy danych i kliknij Dalej.
W przypadku prawdziwej aplikacji musisz wybrać lokalizację znajdującą się w pobliżu użytkowników. - Kliknij Rozpocznij w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł zabezpieczeń.
W dalszej części tego ćwiczenia z programowania dodasz reguły zabezpieczeń, aby zabezpieczyć swoje dane. Nie udostępniaj ani nie udostępniaj publicznie aplikacji bez dodania reguł bezpieczeństwa dla bazy danych. - Kliknij Utwórz.
Konfigurowanie Cloud Storage dla Firebase
- W panelu po lewej stronie konsoli Firebase rozwiń Kompilację i wybierz Miejsce na dane.
- Kliknij Rozpocznij.
- Wybierz lokalizację domyślnego zasobnika Cloud Storage.
Zasobniki w usługachUS-WEST1
,US-CENTRAL1
iUS-EAST1
mogą korzystać z poziomu „Zawsze bezpłatne” w Google Cloud Storage. Zasobniki w innych lokalizacjach podlegają cennikom i zasadom korzystania z Google Cloud Storage. - Kliknij Rozpocznij w trybie testowym. Przeczytaj wyłączenie odpowiedzialności dotyczące reguł zabezpieczeń.
W dalszej części tego ćwiczenia z programowania dodasz reguły zabezpieczeń, aby zabezpieczyć swoje dane. Nie udostępniaj ani nie udostępniaj publicznie aplikacji bez dodania reguł bezpieczeństwa dla zasobnika Storage. - Kliknij Utwórz.
4. Przejrzyj bazę kodu startową
W tej sekcji przyjrzysz się kilku obszarom podstawowego kodu źródłowego aplikacji, do których w ramach tego Codelab dodasz funkcje.
Struktura folderów i plików
Poniższa tabela zawiera omówienie struktury folderów i plików aplikacji:
Foldery i pliki | Opis |
| Komponenty React do filtrów, nagłówków, szczegółów restauracji i opinii |
| Funkcje użytkowe, które nie są koniecznie powiązane z React lub Next.js |
| Kod i konfiguracja Firebase |
| zasoby statyczne w aplikacji internetowej, takie jak ikony. |
| Routing przy użyciu routera aplikacji Next.js |
| Obsługa trasy interfejsu API |
| Zależności projektu w npm |
| Konfiguracja specyficzna dla Next.js (czynności serwera są włączone) |
| Konfiguracja usługi językowej JavaScript |
Komponenty serwera i klienta
Jest to aplikacja internetowa Next.js, która używa routera aplikacji. Renderowanie serwera jest używane w całej aplikacji. Na przykład plik src/app/page.js
jest komponentem serwera odpowiedzialnym za stronę główną. Plik src/components/RestaurantListings.jsx
to komponent klienta oznaczony dyrektywą "use client"
na początku pliku.
Importuj instrukcje
Możesz zauważyć instrukcje importu podobne do tej:
import RatingPicker from "@/src/components/RatingPicker.jsx";
Aplikacja używa symbolu @
, aby uniknąć zbędnych ścieżek importu względnego. Jest to możliwe dzięki aliasom ścieżek.
Interfejsy API Firebase
Cały kod interfejsu API Firebase jest zapakowany w katalogu src/lib/firebase
. Zamiast importować funkcje Firebase bezpośrednio, poszczególne komponenty React zaimportują opakowane funkcje z katalogu src/lib/firebase
.
Dane testowe
Plik src/lib/randomData.js
zawiera dane o fikcyjnych restauracjach i recenzjach. Dane z tego pliku są łączone w kodzie w pliku src/lib/fakeRestaurants.js
.
5. Utwórz backend App Hosting
W tej sekcji skonfigurujesz backend usługi tworzenia aplikacji, aby obserwować gałąź w repozytorium Git.
Na końcu tej sekcji będziesz mieć połączony backend App Hosting z Twoim repozytorium w GitHubie, który będzie automatycznie ponownie skompilować i wdrożyć nową wersję Twojej aplikacji za każdym razem, gdy wypchniesz nowe zatwierdzenie do gałęzi main
.
Wdrażanie reguł zabezpieczeń
Ten kod ma już zestawy reguł zabezpieczeń dla Firestore oraz Cloud Storage dla Firebase. Po wdrożeniu reguł zabezpieczeń dane w bazie danych i zasobniku są lepiej chronione przed niewłaściwym wykorzystaniem.
- W terminalu skonfiguruj interfejs wiersza poleceń tak, aby używał utworzonego wcześniej projektu Firebase:
Gdy pojawi się prośba o podanie aliasu, wpiszfirebase use --add
friendlyeats-codelab
. - Aby wdrożyć te reguły zabezpieczeń, uruchom w terminalu to polecenie:
firebase deploy --only firestore:rules,storage
- Jeśli zapytamy:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, naciśnijEnter
, aby wybrać Tak.
Dodawanie konfiguracji Firebase do kodu aplikacji internetowej
- W konsoli Firebase otwórz Ustawienia projektu.
- Aby zarejestrować nową aplikację internetową, w panelu Konfiguracja i ustawienie SDK kliknij „Dodaj aplikację” i ikonę klamer kodowych
.
- Na końcu procesu tworzenia aplikacji internetowej skopiuj zmienną
firebaseConfig
i skopiuj jej właściwości wraz z wartościami. - Otwórz plik
apphosting.yaml
w edytorze kodu i uzupełnij wartości zmiennych środowiskowych wartościami konfiguracyjnymi z konsoli Firebase. - Zastąp obecne właściwości w pliku tymi, które zostały skopiowane.
- Zapisz plik.
Utworzenie backendu
- Otwórz w konsoli Firebase stronę Hosting aplikacji:
- Aby rozpocząć proces tworzenia backendu, kliknij „Rozpocznij”. Skonfiguruj backend w ten sposób:
- Postępuj zgodnie z instrukcjami wyświetlanymi w pierwszym kroku, aby połączyć utworzone wcześniej repozytorium GitHub.
- Ustaw ustawienia wdrażania:
- Zachowaj katalog główny jako
/
- Ustaw aktywną gałąź na
main
- Włączanie automatycznego wdrażania
- Zachowaj katalog główny jako
- Nazwij backend
friendlyeats-codelab
. - W sekcji „Utwórz lub powiąż aplikację internetową Firebase” z menu „Wybierz istniejącą aplikację internetową Firebase” wybierz skonfigurowaną wcześniej aplikację internetową.
- Kliknij „Zakończ i wdróż”. Po chwili przeniesiemy Cię na nową stronę, na której możesz sprawdzić stan nowego backendu usługi Hostowanie aplikacji.
- Po zakończeniu wdrażania kliknij swoją bezpłatną domenę w sekcji „Domeny”. Rozpoczęcie pracy może potrwać kilka minut z powodu rozpowszechnienia DNS.
Udało Ci się wdrożyć początkową aplikację internetową. Za każdym razem, gdy wypchniesz nowe zatwierdzenie do gałęzi main
repozytorium GitHub, w konsoli Firebase rozpocznie się nowa kompilacja i wdrażanie, a Twoja witryna zostanie automatycznie zaktualizowana po zakończeniu wdrażania.
6. Dodawanie uwierzytelniania do aplikacji internetowej
W tej sekcji dodasz uwierzytelnianie do aplikacji internetowej, aby umożliwić Ci logowanie się do niej.
Implementowanie funkcji logowania i wylogowywania
- W pliku
src/lib/firebase/auth.js
zastąp funkcjeonAuthStateChanged
,signInWithGoogle
isignOut
tym kodem:
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);
}
}
Ten kod korzysta z tych interfejsów API Firebase:
Interfejs Firebase API | Opis |
Tworzy instancję dostawcy uwierzytelniania Google. | |
Uruchamia proces uwierzytelniania w oknie. | |
Wylogowuje użytkownika. |
W pliku src/components/Header.jsx
kod wywołuje już funkcje signInWithGoogle
i signOut
.
- Utwórz zatwierdzenie z komunikatem „Dodawanie uwierzytelniania Google” i prześlij je do repozytorium GitHub. 1. W konsoli Firebase otwórz stronę Hosting aplikacji i zaczekaj na zakończenie nowego wdrożenia.
- W aplikacji internetowej odśwież stronę i kliknij Zaloguj się przez Google. Aplikacja internetowa się nie aktualizuje, więc nie ma pewności, czy logowanie się udało.
Wysyłanie stanu uwierzytelniania na serwer
Aby przekazywać stan uwierzytelniania do serwera, używamy skryptu service worker. Zastąp funkcje fetchWithFirebaseHeaders
i getAuthIdToken
tym kodem:
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);
}
Odczytywanie stanu uwierzytelniania na serwerze
Użyjemy FirebaseServerApp, aby odzwierciedlić stan uwierzytelniania klienta na serwerze.
Otwórz plik src/lib/firebase/serverApp.js
i zastąp funkcję 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 };
}
Subskrypcja zmian dotyczących uwierzytelniania
Aby zasubskrybować zmiany dotyczące uwierzytelniania, wykonaj te czynności:
- Przejdź do pliku
src/components/Header.jsx
. - Zastąp funkcję
useUserSession
tym kodem:
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;
}
Ten kod używa haku state w React, aby aktualizować użytkownika, gdy funkcja onAuthStateChanged
określi, że nastąpiła zmiana stanu uwierzytelniania.
Weryfikowanie zmian
Układ główny w pliku src/app/layout.js
renderuje nagłówek i przekazuje użytkownika jako argument (jeśli jest dostępny).
<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 cyklu życia strony po pierwszym wczytaniu strony pojawią się jakieś aktualizacje uwierzytelniania, moduł obsługi onAuthStateChanged
je zajmie.
Teraz nadszedł czas na wdrożenie nowej wersji i sprawdzenie jej.
- Utwórz zatwierdzanie z komunikatem „Pokaż stan logowania” i prześlij je do repozytorium GitHub.
- Otwórz stronę App Hosting (Hosting aplikacji) w konsoli Firebase i poczekaj na zakończenie nowego wdrożenia.
- Sprawdź nowy sposób uwierzytelniania:
- W przeglądarce odśwież aplikację internetową. W nagłówku pojawi się Twoja nazwa wyświetlana.
- Wyloguj się i zaloguj ponownie. Strona jest aktualizowana w czasie rzeczywistym bez jej odświeżania. Możesz powtórzyć ten krok dla różnych użytkowników.
- Opcjonalnie: kliknij aplikację internetową prawym przyciskiem myszy, wybierz Wyświetl źródło strony i wyszukaj wyświetlaną nazwę. Występuje w surowym kodzie HTML zwróconym z serwera.
7. Wyświetlanie informacji o restauracjach
Aplikacja internetowa zawiera przykładowe dane o restauracjach i recenzjach.
Dodaj co najmniej jedną restaurację
Aby wstawić dane przykładowej restauracji do lokalnej bazy danych Cloud Firestore, wykonaj te czynności:
- W aplikacji internetowej kliknij > Dodaj przykładowe restauracje.
- W konsoli Firebase na stronie Baza danych Firestore wybierz restauracje. W kolekcji restauracji zobaczysz najwyższego poziomu dokumenty, z których każdy reprezentuje restaurację.
- Kliknij kilka dokumentów, aby zobaczyć właściwości dokumentu dotyczącego restauracji.
Wyświetlanie listy restauracji
Twoja baza danych Cloud Firestore zawiera teraz restauracje, które aplikacja internetowa Next.js może wyświetlać.
Aby zdefiniować kod pobierania danych:
- W pliku
src/app/page.js
znajdź komponent serwera<Home />
i zapoznaj się z wywołaniem funkcjigetRestaurants
, która pobiera listę restauracji w czasie działania serwera. FunkcjęgetRestaurants
implementujesz w poniższych krokach. - W pliku
src/lib/firebase/firestore.js
zastąp funkcjeapplyQueryFilters
igetRestaurants
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(),
};
});
}
- Utwórz zatwierdzenie z komunikatem zatwierdzenia „Odczytaj listę restauracji z Firestore” i wypchnij je do repozytorium GitHub.
- Otwórz stronę App Hosting (Hosting aplikacji) w konsoli Firebase i poczekaj na zakończenie nowego wdrożenia.
- W aplikacji internetowej odśwież stronę. Obrazy z restauracji pojawiają się na stronie jako kafelki.
Sprawdzanie, czy informacje o restauracjach wczytują się podczas działania serwera
W ramach frameworku Next.js trudno określić, czy dane są wczytywane po stronie serwera, czy po stronie klienta.
Aby sprawdzić, czy wizytówki restauracji wczytują się w czasie działania serwera, wykonaj te czynności:
- W aplikacji internetowej otwórz Narzędzia deweloperskie i wyłącz JavaScript.
- Odśwież aplikację internetową. Wizytówki restauracji nadal się wczytają. Informacje o restauracji są zwracane w odpowiedzi serwera. Gdy JavaScript jest włączony, informacje o restauracji są hydratyzowane za pomocą kodu JavaScript po stronie klienta.
- W Narzędziach deweloperskich ponownie włącz JavaScript.
Nasłuchiwanie aktualizacji restauracji za pomocą odbiorników zrzutów Cloud Firestore
W poprzedniej sekcji pokazaliśmy, jak początkowy zestaw restauracji wczytywał się z pliku src/app/page.js
. Plik src/app/page.js
to komponent serwera, który jest renderowany na serwerze, w tym kod pobierania danych Firebase.
Plik src/components/RestaurantListings.jsx
jest komponentem klienckim i można go skonfigurować tak, by hydratował znaczniki renderowane przez serwer.
Aby skonfigurować plik src/components/RestaurantListings.jsx
do hydratacji znaczników renderowanych przez serwer, wykonaj te czynności:
- W pliku
src/components/RestaurantListings.jsx
zwróć uwagę na poniższy kod, który został już dla Ciebie napisany:
useEffect(() => {
const unsubscribe = getRestaurantsSnapshot(data => {
setRestaurants(data);
}, filters);
return () => {
unsubscribe();
};
}, [filters]);
Ten kod wywołuje funkcję getRestaurantsSnapshot()
, która jest podobna do funkcji getRestaurants()
zaimplementowanej w poprzednim kroku. Funkcja zrzutu zawiera jednak mechanizm wywołania zwrotnego, który jest wywoływany za każdym razem, gdy w zbiorze restauracji zostanie wprowadzona zmiana.
- 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);
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;
}
Zmiany wprowadzane na stronie Baza danych Firestore są teraz odzwierciedlane w aplikacji internetowej w czasie rzeczywistym.
- Utwórz zatwierdzenie z komunikatem „Listen for realtime restaurant updates” i prześlij je do repozytorium GitHub.
- W konsoli Firebase otwórz stronę Hosting aplikacji i poczekaj na zakończenie nowego wdrożenia.
- W aplikacji internetowej kliknij > Dodaj przykładowe restauracje. Jeśli funkcja zrzutu jest prawidłowo zaimplementowana, restauracje wyświetlają się w czasie rzeczywistym bez odświeżania strony.
8. Zapisywanie opinii przesłanych przez użytkowników z aplikacji internetowej
- 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 aktualne dane o liczbie ocen i średniej obliczonej ocenie.
- 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;
}
}
Wdróż działanie serwera Next.js
Akcją serwera Next.js jest wygodny interfejs API umożliwiający dostęp do danych formularza, np. data.get("text")
, aby uzyskać wartość tekstową z ładunku przesłania formularza.
Aby do przetworzenia formularza weryfikacji użyć akcji serwera Next.js, wykonaj te czynności:
- W pliku
src/components/ReviewDialog.jsx
znajdź atrybutaction
w elemencie<form>
.
<form action={handleReviewFormSubmission}>
Wartość atrybutu action
odnosi się do funkcji, którą zaimplementujesz w następnym kroku.
- 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
Udało Ci się wdrożyć obsługę przesyłania opinii, więc możesz teraz sprawdzić, czy recenzje są prawidłowo wstawiane do Cloud Firestore.
Aby dodać opinię i sprawdzić, czy jest ona wstawiona do Cloud Firestore, wykonaj te czynności:
- Utwórz zatwierdzenie z komunikatem „Zezwalaj użytkownikom na przesyłanie opinii o restauracjach” i prześlij je do repozytorium GitHub.
- Otwórz stronę App Hosting (Hosting aplikacji) w konsoli Firebase i poczekaj na zakończenie nowego wdrożenia.
- Odśwież aplikację internetową i na stronie głównej wybierz restaurację.
- Na stronie restauracji kliknij .
- Wybierz liczbę gwiazdek.
- Napisz opinię.
- Kliknij Prześlij. Opinia pojawi się u góry listy opinii.
- W Cloud Firestore wyszukaj w panelu Dodaj dokument dokument restauracji, który został przez Ciebie sprawdzony, i wybierz go.
- W panelu Rozpocznij kolekcję wybierz oceny.
- W panelu Dodaj dokument znajdź dokument do sprawdzenia, aby sprawdzić, czy został wstawiony zgodnie z oczekiwaniami.
9. Zapisywanie plików przesłanych przez użytkowników z aplikacji internetowej
W tej sekcji dodasz funkcje, które po zalogowaniu umożliwiają zastępowanie obrazu powiązanego z restauracją. Przesyłasz obraz do Firebase Storage i aktualizujesz adres URL obrazu w dokumencie Cloud Firestore, który reprezentuje restaurację.
Aby zapisać pliki przesłane przez użytkowników za pomocą aplikacji internetowej, wykonaj te czynności:
- Obserwuj w pliku
src/components/Restaurant.jsx
kod, który uruchamia się, 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);
setRestaurant({ ...restaurant, photo: imageURL });
}
Nie musisz wprowadzać żadnych zmian, ale w kolejnych krokach wdrożysz działanie funkcji updateRestaurantImage()
.
- W pliku
src/lib/firebase/storage.js
zastąp funkcjeupdateRestaurantImage()
iuploadImage()
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()
została już wdrożona. Ta funkcja aktualizuje istniejący dokument restauracji w Cloud Firestore, dodając do niego zaktualizowany adres URL obrazu.
Sprawdzanie funkcji przesyłania obrazów
Aby sprawdzić, czy obrazy są przesyłane zgodnie z oczekiwaniami:
- Utwórz zatwierdzenie z wiadomością „Zezwalaj użytkownikom na zmianę zdjęcia każdej restauracji” i prześlij je do repozytorium GitHub.
- Otwórz stronę App Hosting (Hosting aplikacji) w konsoli Firebase i poczekaj na zakończenie nowego wdrożenia.
- W aplikacji internetowej sprawdź, czy jesteś zalogowany(-a), i wybierz restaurację.
- Kliknij i prześlij obraz z systemu plików. Obraz opuszcza środowisko lokalne i zostaje przesłany do Cloud Storage. Obraz pojawi się od razu po jego przesłaniu.
- Otwórz Cloud Storage dla Firebase.
- Otwórz folder reprezentujący restaurację. Przesłany obraz znajduje się w folderze.
10. Streszczanie opinii o restauracjach za pomocą generatywnej AI
W tej sekcji dodasz funkcję podsumowania opinii, aby użytkownik mógł szybko dowiedzieć się, co inni myślą o restauracji, bez konieczności czytania każdej opinii.
Przechowywanie klucza interfejsu Gemini API w usłudze Cloud Secret Manager
- Aby korzystać z interfejsu Gemini API, musisz mieć klucz interfejsu API. Utwórz klucz w Google AI Studio.
- App Hosting integruje się z usługą Cloud Secret Manager, co umożliwia bezpieczne przechowywanie poufnych wartości, takich jak klucze interfejsu API:
- Aby utworzyć nowy obiekt tajny, uruchom w terminalu to polecenie:
firebase apphosting:secrets:set gemini-api-key
- Gdy pojawi się prośba o wartość tajną, skopiuj i wklej klucz interfejsu Gemini API z Google AI Studio.
- Gdy pojawi się pytanie, czy nowy klucz powinien zostać dodany do
apphosting.yaml
, wpiszY
, aby zaakceptować.
Klucz interfejsu Gemini API jest teraz bezpiecznie przechowywany w usłudze Cloud Secret Manager i jest dostępny dla backendu usługi hostowania aplikacji.
Implementowanie komponentu podsumowania opinii
- W
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 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>; } }
- Utwórz zatwierdzanie z komunikatem „Użyj AI do podsumowywania opinii” i prześlij je do repozytorium GitHub.
- Otwórz stronę App Hosting (Hosting aplikacji) w konsoli Firebase i poczekaj na zakończenie nowego wdrożenia.
- Otwórz stronę restauracji. U góry powinno pojawić się jednozdaniowe podsumowanie wszystkich opinii na stronie.
- Dodaj nową opinię i odśwież stronę. Podsumowanie zmian powinno być widoczne.
11. Podsumowanie
Gratulacje! Dowiedz się, jak za pomocą Firebase dodać funkcje do aplikacji Next.js. W szczególności wykorzystano te elementy:
- Firebase App Hosting do automatycznego kompilowania i wdrażania kodu Next.js za każdym razem, gdy przenosisz go do skonfigurowanej gałęzi.
- Uwierzytelnianie Firebase, aby włączyć funkcję logowania i wylogowywania się.
- Cloud Firestore: dane restauracji i opinie o restauracjach.
- Cloud Storage dla Firebase na potrzeby zdjęć restauracji.