1. לפני שמתחילים
בסדנת התכנות הזו תלמדו איך לשלב את Firebase עם אפליקציית אינטרנט של Next.js שנקראת Friendly Eats, שהיא אתר לביקורות על מסעדות.
אפליקציית האינטרנט המוגמרת מציעה תכונות שימושיות שמדגימות איך Firebase יכול לעזור לכם לבנות אפליקציות Next.js. התכונות האלה כוללות:
- יצירה ופריסה אוטומטיות: ב-codelab הזה נעשה שימוש ב-Firebase App Hosting כדי ליצור ולפרוס באופן אוטומטי את קוד Next.js בכל פעם שמעלים אותו לענף מוגדר.
- כניסה ויציאה: אפליקציית האינטרנט המלאה מאפשרת לכם להיכנס באמצעות חשבון Google ולצאת ממנו. הכניסה של המשתמשים וההתמדה שלהם מנוהלות באופן מלא דרך אימות ב-Firebase.
- תמונות: אפליקציית האינטרנט שהושלמה מאפשרת למשתמשים מחוברים להעלות תמונות של מסעדות. נכסי התמונות מאוחסנים ב-Cloud Storage for Firebase. Firebase JavaScript SDK מספק כתובת URL ציבורית לתמונות שהועלו. כתובת ה-URL הציבורית הזו מאוחסנת במסמך המסעדה הרלוונטי ב-Cloud Firestore.
- ביקורות: אפליקציית האינטרנט המלאה מאפשרת למשתמשים מחוברים לפרסם ביקורות על מסעדות. הביקורות כוללות דירוג כוכבים והודעה מבוססת-טקסט. המידע על הביקורות מאוחסן ב-Cloud Firestore.
- מסננים: אפליקציית האינטרנט המלאה מאפשרת למשתמשים מחוברים לסנן את רשימת המסעדות לפי קטגוריה, מיקום ומחיר. אפשר גם להתאים אישית את שיטת המיון שבה משתמשים. הגישה לנתונים מתבצעת מ-Cloud Firestore, והשאילתות ב-Firestore מוחלות על סמך המסננים שבהם נעשה שימוש.
דרישות מוקדמות
- חשבון GitHub
- ידע ב-Next.js וב-JavaScript
מה תלמדו
- איך משתמשים ב-Firebase עם נתב האפליקציות של Next.js ועם עיבוד בצד השרת.
- איך שומרים תמונות ב-Cloud Storage for Firebase.
- איך קוראים וכותבים נתונים במסד נתונים של Cloud Firestore.
- איך משתמשים בפיצ'ר 'כניסה באמצעות חשבון Google' עם Firebase JavaScript SDK.
מה צריך להכין
- Git
- גרסה יציבה עדכנית של Node.js
- דפדפן לבחירתכם, כמו Google Chrome
- סביבת פיתוח עם עורך קוד וטרמינל
- חשבון Google ליצירה ולניהול של פרויקט Firebase
- האפשרות לשדרג את פרויקט Firebase לתוכנית התמחור Blaze
2. הגדרת סביבת הפיתוח ומאגר ב-GitHub
ב-codelab הזה מסופק בסיס הקוד של האפליקציה, והוא מסתמך על Firebase CLI.
יצירת מאגר ב-GitHub
אפשר למצוא את המקור של ה-Codelab בכתובת https://github.com/firebase/friendlyeats-web. המאגר מכיל פרויקטים לדוגמה למספר פלטפורמות. עם זאת, ב-codelab הזה נעשה שימוש רק בספרייה nextjs-start
. חשוב לשים לב לספריות הבאות:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
מעתיקים את התיקייה nextjs-start
למאגר משלכם:
- באמצעות מסוף, יוצרים תיקייה חדשה במחשב ועוברים לספרייה החדשה:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- משתמשים בחבילת ה-npm giget כדי לאחזר רק את התיקייה
nextjs-start
:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- מעקב אחרי שינויים באופן מקומי באמצעות Git:
git init git add . git commit -m "codelab starting point" git branch -M main
- יוצרים מאגר חדש ב-GitHub: https://github.com/new. נותנים לו שם שרוצים.
- מעתיקים את כתובת ה-URL החדשה שנוצרה ב-GitHub. היא תיראה כך:
-
https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git
או git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
-
- מריצים את הפקודה הבאה כדי לדחוף את השינויים המקומיים למאגר החדש ב-GitHub. מחליפים את הפלייס הולדר
<REPOSITORY_URL>
בכתובת ה-URL של המאגר בפועל.git remote add origin <REPOSITORY_URL> git push -u origin main
- עכשיו אמור להופיע קוד ההתחלה במאגר GitHub.
התקנה או עדכון של Firebase CLI
מריצים את הפקודה הבאה כדי לוודא שה-CLI של Firebase מותקן ושהגרסה שלו היא 14.1.0 ואילך:
firebase --version
אם מופיעה גרסה ישנה יותר או אם Firebase CLI לא מותקן, מריצים את פקודת ההתקנה:
npm install -g firebase-tools@latest
אם אתם לא מצליחים להתקין את Firebase CLI בגלל שגיאות הרשאה, תוכלו לעיין במסמכי התיעוד של npm או להשתמש באפשרות התקנה אחרת.
התחברות ל-Firebase
- מריצים את הפקודה הבאה כדי להתחבר ל-Firebase CLI:
firebase login
- מזינים
Y
אוN
, בהתאם לרצון שלכם ש-Firebase יאסוף נתונים. - בדפדפן, בוחרים את חשבון Google ולוחצים על אישור.
3. הגדרת פרויקט Firebase
בקטע הזה תגדירו פרויקט Firebase ותקשרו אליו אפליקציית אינטרנט של Firebase. תגדירו גם את שירותי Firebase שבהם נעשה שימוש באפליקציית האינטרנט לדוגמה.
יצירת פרויקט Firebase
- נכנסים למסוף Firebase באמצעות אותו חשבון Google שבו השתמשתם בשלב הקודם.
- לוחצים על הלחצן כדי ליצור פרויקט חדש, ואז מזינים שם לפרויקט (לדוגמה,
FriendlyEats Codelab
).
- לוחצים על המשך.
- אם מוצגת בקשה לעשות זאת, קוראים ומאשרים את התנאים של Firebase, ואז לוחצים על המשך.
- (אופציונלי) מפעילים את העזרה מבוססת-AI במסוף Firebase (שנקראת Gemini ב-Firebase).
- ב-codelab הזה לא צריך להשתמש ב-Google Analytics, ולכן משביתים את האפשרות Google Analytics.
- לוחצים על יצירת פרויקט, מחכים שהפרויקט יוקצה ולוחצים על המשך.
שדרוג תוכנית התמחור של Firebase
כדי להשתמש ב-Firebase App Hosting וב-Cloud Storage for Firebase, הפרויקט ב-Firebase צריך להיות בתוכנית התמחור 'תשלום לפי שימוש' (Blaze), כלומר הוא צריך להיות מקושר לחשבון לחיוב ב-Cloud.
- בחשבון לחיוב ב-Cloud צריך להגדיר אמצעי תשלום, כמו כרטיס אשראי.
- אם אתם חדשים ב-Firebase וב-Google Cloud, כדאי לבדוק אם אתם עומדים בדרישות לקבלת קרדיט בסך 300$וחשבון לחיוב ב-Cloud עם תקופת ניסיון בחינם.
- אם אתם משתתפים בסדנת קוד כחלק מאירוע, כדאי לשאול את מארגן האירוע אם יש קרדיטים ל-Cloud.
כדי לשדרג את הפרויקט לתוכנית Blaze, פועלים לפי השלבים הבאים:
- במסוף Firebase, בוחרים באפשרות שדרוג התוכנית.
- בוחרים בתוכנית Blaze. פועלים לפי ההוראות במסך כדי לקשר חשבון לחיוב ב-Cloud לפרויקט.
אם הייתם צריכים ליצור חשבון לחיוב ב-Cloud כחלק מהשדרוג, יכול להיות שתצטרכו לחזור לתהליך השדרוג במסוף Firebase כדי להשלים את השדרוג.
הוספת אפליקציית אינטרנט לפרויקט Firebase
- עוברים אל סקירת הפרויקט בפרויקט Firebase ולוחצים על
אינטרנט.
אם כבר רשמתם אפליקציות בפרויקט, לוחצים על הוספת אפליקציה כדי לראות את הסמל של אינטרנט. - בתיבת הטקסט App nickname (כינוי לאפליקציה), מזינים כינוי קליט לאפליקציה, כמו
My Next.js app
. - משאירים את תיבת הסימון Also set up Firebase Hosting for this app (הגדרת אירוח ב-Firebase גם לאפליקציה הזו) לא מסומנת.
- לוחצים על Register app > Continue to console (רישום האפליקציה > המשך אל המסוף).
הגדרה של שירותי Firebase במסוף Firebase
הגדרת אימות
- במסוף Firebase, עוברים אל אימות.
- לוחצים על תחילת העבודה.
- בעמודה ספקים נוספים, לוחצים על Google > הפעלה.
- בתיבת הטקסט Public-facing name for project, מזינים שם קליט, כמו
My Next.js app
. - בתפריט הנפתח Support email for project, בוחרים את כתובת האימייל.
- לוחצים על שמירה.
הגדרת Cloud Firestore
- בחלונית הימנית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Firestore Database.
- לוחצים על יצירת מסד נתונים.
- משאירים את הערך
(default)
בשדה מזהה מסד הנתונים. - בוחרים מיקום למסד הנתונים ולוחצים על הבא.
באפליקציה אמיתית, כדאי לבחור מיקום שקרוב למשתמשים. - לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור בנוגע לכללי האבטחה.
בהמשך ה-codelab הזה, תוסיפו כללי אבטחה כדי לאבטח את הנתונים. אל תפיצו או תחשפו אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה למסד הנתונים. - לוחצים על יצירה.
הגדרת Cloud Storage for Firebase
- בחלונית הימנית במסוף Firebase, מרחיבים את Build (פיתוח) ובוחרים באפשרות Storage (אחסון).
- לוחצים על תחילת העבודה.
- בוחרים מיקום לקטגוריית האחסון שמוגדרת כברירת מחדל.
קטגוריות ב-US-WEST1
, ב-US-CENTRAL1
וב-US-EAST1
יכולות ליהנות מהמסלול תמיד בחינם של Google Cloud Storage. התמחור והשימוש בקטגוריות בכל המיקומים האחרים מפורטים בתמחור ובשימוש ב-Google Cloud Storage. - לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור בנוגע לכללי האבטחה.
בהמשך ה-codelab, תוסיפו כללי אבטחה כדי לאבטח את הנתונים. אל תפיצו או תחשפו אפליקציה לציבור בלי להוסיף כללי אבטחה לדלי שלכם ב-Storage. - לוחצים על יצירה.
פריסת כללי אבטחה
בקוד כבר יש קבוצות של כללי אבטחה ל-Firestore ול-Cloud Storage for Firebase. אחרי שמפעילים את כללי האבטחה, הנתונים במסד הנתונים ובמאגר מוגנים טוב יותר מפני שימוש לרעה.
- בטרמינל, מגדירים את ה-CLI לשימוש בפרויקט Firebase שיצרתם קודם:
כשמופיעה בקשה להזין כינוי, מזיניםfirebase use --add
friendlyeats-codelab
. - כדי לפרוס את כללי האבטחה האלה (וגם אינדקסים שיידרשו בהמשך), מריצים את הפקודה הבאה בטרמינל:
firebase deploy --only firestore,storage
- אם מוצגת השאלה:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, מקישים עלEnter
כדי לבחור באפשרות כן.
4. בדיקת בסיס הקוד הראשוני
בקטע הזה נסקור כמה אזורים בבסיס הקוד של האפליקציה, שאליהם נוסיף פונקציונליות בסדנת הקוד הזו.
מבנה התיקיות והקבצים
בטבלה הבאה מוצגת סקירה כללית של מבנה התיקיות והקבצים של האפליקציה:
תיקיות וקבצים | תיאור |
| רכיבי React למסננים, לכותרות, לפרטי מסעדות ולביקורות |
| פונקציות עזר שלא בהכרח קשורות ל-React או ל-Next.js |
| קוד ספציפי ל-Firebase והגדרת Firebase |
| נכסים סטטיים באפליקציית האינטרנט, כמו סמלים |
| ניתוב באמצעות נתב האפליקציות של Next.js |
| יחסי תלות של פרויקטים ב-npm |
| הגדרה ספציפית ל-Next.js (פעולות שרת מופעלות) |
| הגדרות של שירות שפה ב-JavaScript |
רכיבי שרת ולקוח
האפליקציה היא אפליקציית אינטרנט ב-Next.js שמשתמשת בנתב האפליקציות. הרינדור בצד השרת משמש בכל האפליקציה. לדוגמה, קובץ src/app/page.js
הוא רכיב שרת שאחראי על הדף הראשי. הקובץ src/components/RestaurantListings.jsx
הוא רכיב לקוח שמסומן על ידי ההנחיה "use client"
בתחילת הקובץ.
ייבוא דפי פירוט חשבון
יכול להיות שתראו הצהרות ייבוא כמו אלה:
import RatingPicker from "@/src/components/RatingPicker.jsx";
האפליקציה משתמשת בסמל @
כדי להימנע מנתיבי ייבוא יחסיים מסורבלים, והיא עושה זאת באמצעות כינויי נתיבים.
ממשקי API ספציפיים ל-Firebase
כל קוד Firebase API עטוף בספרייה src/lib/firebase
. לאחר מכן, כל רכיב React מייבא את הפונקציות העטופות מהספרייה src/lib/firebase
, במקום לייבא ישירות פונקציות של Firebase.
נתוני דמה
נתוני מסעדות וביקורות לדוגמה מופיעים בקובץ src/lib/randomData.js
. הנתונים מהקובץ הזה מורכבים בקוד בקובץ src/lib/fakeRestaurants.js
.
5. יצירת קצה עורפי לאירוח אפליקציות
בקטע הזה מגדירים קצה עורפי של אירוח אפליקציות כדי לעקוב אחרי ענף במאגר git.
בסוף הקטע הזה יהיה לכם קצה עורפי של App Hosting שמחובר למאגר שלכם ב-GitHub, שיבנה מחדש באופן אוטומטי וישיק גרסה חדשה של האפליקציה בכל פעם שתדחפו קומיט חדש לענף main
.
יצירת קצה עורפי
- עוברים אל דף אירוח האפליקציות במסוף Firebase:
- כדי להתחיל בתהליך היצירה של ה-Backend, לוחצים על 'התחלה'. מגדירים את הקצה העורפי באופן הבא:
- בוחרים אזור. באפליקציה אמיתית, צריך לבחור את האזור שהכי קרוב למשתמשים.
- פועלים לפי ההנחיות בשלב 'ייבוא מאגר GitHub' כדי לחבר את מאגר GitHub שיצרתם קודם.
- קובעים את הגדרות הפריסה:
- השארת ספריית השורש כ
/
- הגדרת הענף הפעיל ל-
main
- הפעלת השקות אוטומטיות
- השארת ספריית השורש כ
- נותנים שם לחלק האחורי של האתר
friendlyeats-codelab
. - בקטע 'שיוך אפליקציית אינטרנט ב-Firebase', לוחצים על 'יצירת אפליקציית אינטרנט חדשה ב-Firebase'.
- לוחצים על Finish and deploy (סיום ופריסה). אחרי רגע תועברו לדף חדש שבו תוכלו לראות את הסטטוס של העורף החדש של אירוח האפליקציה.
- אחרי שההשקה תסתיים, לוחצים על הדומיין החינמי בקטע 'דומיינים'. יכול להיות שיעברו כמה דקות עד שהשינוי יתעדכן ב-DNS.
- אוי ואבוי! כשמטעינים את הדף, מופיעה הודעת שגיאה: "שגיאת אפליקציה: אירעה חריגה בצד השרת (למידע נוסף, אפשר לעיין ביומני השרת)".
- במסוף Firebase, בודקים את הכרטיסייה Logs (יומני רישום) של העורף של App Hosting. יוצג יומן עם השגיאה 'לא הוטמעה'. בשלב הבא, כשנוסיף אימות, נתקן את זה.
הפעלתם את אפליקציית האינטרנט הראשונה. בכל פעם שתדחפו קומיט חדש לענף main
במאגר GitHub, תראו בנייה חדשה והשקה שמתחילות במסוף Firebase, והאתר שלכם יתעדכן אוטומטית כשההשקה תסתיים.
6. הוספת אימות לאפליקציית האינטרנט
בסעיף הזה מוסיפים אימות לאפליקציית האינטרנט כדי שתוכלו להתחבר אליה.
הוספת דומיין מורשה
אימות ב-Firebase יקבל רק בקשות כניסה מדומיינים שאתם מאשרים. בשלב הזה, נוסיף את הדומיין של ה-backend של אירוח האפליקציות לרשימת הדומיינים המאושרים בפרויקט.
- מעתיקים את הדומיין של העורף של אירוח האפליקציה מהדף 'סקירה כללית' של אירוח האפליקציה.
- עוברים לכרטיסייה Auth Settings ובוחרים באפשרות Authorized Domains (דומיינים מורשים).
- לוחצים על הלחצן הוספת דומיין.
- מזינים את הדומיין של ה-backend של App Hosting.
- לוחצים על הוספה.
הטמעה של פונקציות הכניסה והיציאה
- בקובץ
src/lib/firebase/auth.js
, מחליפים את הפונקציותonAuthStateChanged
,onIdTokenChanged
,signInWithGoogle
ו-signOut
בקוד הבא:
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);
}
}
הקוד הזה משתמש בממשקי ה-API הבאים של Firebase:
Firebase API | תיאור |
הפונקציה מוסיפה צופה לשינויים בסטטוס הכניסה של המשתמש. | |
הפונקציה מוסיפה צופה לשינויים באסימון ה-ID של המשתמש. | |
יצירת מופע של ספק אימות של Google. | |
מתחיל תהליך אימות מבוסס-דיאלוג. | |
יציאה מהחשבון של המשתמש. |
בקובץ src/components/Header.jsx
, הקוד כבר מפעיל את הפונקציות signInWithGoogle
ו-signOut
.
שליחת מצב האימות לשרת
כדי להעביר את מצב האימות לשרת, נשתמש בקובצי Cookie. בכל פעם שמצב האימות משתנה בלקוח, אנחנו מעדכנים את קובץ ה-Cookie __session
.
ב-src/components/Header.jsx
, מחליפים את הפונקציה useUserSession
בקוד הבא:
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;
}
קריאת מצב האימות בשרת
נשתמש ב-FirebaseServerApp כדי לשקף את מצב האימות של הלקוח בשרת.
פותחים את src/lib/firebase/serverApp.js
ומחליפים את הפונקציה 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 };
}
אימות השינויים
פריסת הבסיס בקובץ src/app/layout.js
מעבדת את הכותרת ומעבירה את המשתמש כמאפיין, אם הוא זמין.
<Header initialUser={currentUser?.toJSON()} />
כלומר, רכיב <Header>
מעבד נתוני משתמש, אם הם זמינים, במהלך זמן הריצה של השרת. אם יש עדכוני אימות במהלך מחזור החיים של הדף אחרי הטעינה הראשונית של הדף, הם מטופלים על ידי ה-handler onAuthStateChanged
.
עכשיו הגיע הזמן להשיק גרסה חדשה ולאמת את מה שבניתם.
- יוצרים קומיט עם הודעת הקומיט 'הוספת אימות' ומבצעים push למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase ומחכים עד שההשקה החדשה תושלם.
- מאמתים את התנהגות האימות החדשה:
- בדפדפן, מרעננים את אפליקציית האינטרנט. השם המוצג יופיע בכותרת.
- לצאת מהחשבון ולהיכנס אליו שוב. אפשר לחזור על השלב הזה עם משתמשים אחרים.
- אופציונלי: לוחצים לחיצה ימנית על אפליקציית האינטרנט, בוחרים באפשרות הצגת מקור הדף ומחפשים את השם המוצג. הוא מופיע במקור ה-HTML הגולמי שמוחזר מהשרת.
7. הצגת פרטי המסעדה
אפליקציית האינטרנט כוללת נתונים לדוגמה של מסעדות וביקורות.
הוספה של מסעדה אחת או יותר
כדי להוסיף נתוני מסעדה לדוגמה למסד הנתונים המקומי של Cloud Firestore, פועלים לפי השלבים הבאים:
- אם עדיין לא עשיתם זאת, נכנסים לאפליקציית האינטרנט. לאחר מכן בוחרים באפשרות
> הוספת מסעדות לדוגמה.
- במסוף Firebase, בדף Firestore Database, בוחרים באפשרות restaurants. מוצגים לכם מסמכים ברמה העליונה באוסף המסעדות, שכל אחד מהם מייצג מסעדה.
- כדאי ללחוץ על כמה מסמכים כדי לראות את המאפיינים של מסמך מסעדה.
הצגת רשימת המסעדות
במסד הנתונים של Cloud Firestore יש עכשיו מסעדות שאפליקציית האינטרנט של Next.js יכולה להציג.
כדי להגדיר את הקוד לאחזור הנתונים, פועלים לפי השלבים הבאים:
- בקובץ
src/app/page.js
, מוצאים את רכיב השרת<Home />
ובודקים את הקריאה לפונקציהgetRestaurants
, שמחזירה רשימה של מסעדות בזמן הריצה של השרת. בשלבים הבאים נטמיע את הפונקציהgetRestaurants
. - בקובץ
src/lib/firebase/firestore.js
, מחליפים את הפונקציותapplyQueryFilters
ו-getRestaurants
בקוד הבא:
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(),
};
});
}
- יוצרים קומיט עם הודעת הקומיט Read the list of restaurants from Firestore (קריאת רשימת המסעדות מ-Firestore) ומבצעים push למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase ומחכים עד שההשקה החדשה תושלם.
- באפליקציית האינטרנט, מרעננים את הדף. תמונות של מסעדות מופיעות כמשבצות בדף.
מוודאים שהדפים העסקיים של המסעדה נטענים בזמן הריצה של השרת
כשמשתמשים ב-framework Next.js, יכול להיות שלא ברור מתי הנתונים נטענים בזמן הריצה של השרת או בזמן הריצה בצד הלקוח.
כדי לוודא שהדפים העסקיים של המסעדות נטענים בזמן הריצה של השרת, פועלים לפי השלבים הבאים:
- באפליקציית האינטרנט, פותחים את כלי הפיתוח ומשביתים את JavaScript.
- מרעננים את אפליקציית האינטרנט. רשימות המסעדות עדיין נטענות. פרטי המסעדה מוחזרים בתגובת השרת. כש-JavaScript מופעל, המידע על המסעדה עובר הידרציה באמצעות קוד JavaScript בצד הלקוח.
- בכלי הפיתוח, מפעילים מחדש את JavaScript.
האזנה לעדכונים לגבי מסעדות באמצעות מאזיני תמונת מצב של Cloud Firestore
בקטע הקודם ראיתם איך נטען סט המסעדות הראשוני מקובץ src/app/page.js
. הקובץ src/app/page.js
הוא רכיב בצד השרת והוא מעובד בשרת, כולל קוד אחזור הנתונים של Firebase.
הקובץ src/components/RestaurantListings.jsx
הוא רכיב לקוח שאפשר להגדיר אותו כדי להוסיף נתונים לסימון שמוצג בשרת.
כדי להגדיר את הקובץ src/components/RestaurantListings.jsx
להוספת נתונים לסימון בצד השרת:
- בקובץ
src/components/RestaurantListings.jsx
, בודקים את הקוד הבא שכבר נכתב בשבילכם:
useEffect(() => {
return getRestaurantsSnapshot((data) => {
setRestaurants(data);
}, filters);
}, [filters]);
הקוד הזה מפעיל את הפונקציה getRestaurantsSnapshot()
, שדומה לפונקציה getRestaurants()
שהטמעתם בשלב הקודם. עם זאת, פונקציית הצילום הזו מספקת מנגנון של קריאה חוזרת, כך שהקריאה החוזרת מופעלת בכל פעם שמתבצע שינוי בקולקציית המסעדות.
- בקובץ
src/lib/firebase/firestore.js
, מחליפים את הפונקציהgetRestaurantsSnapshot()
בקוד הבא:
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);
});
}
שינויים שבוצעו בדף Firestore Database משתקפים עכשיו באפליקציית האינטרנט בזמן אמת.
- יוצרים קומיט עם הודעת הקומיט Listen for realtime restaurant updates (האזנה לעדכונים בזמן אמת של מסעדות) ומבצעים push למאגר GitHub.
- פותחים את הדף App Hosting במסוף Firebase ומחכים עד שההשקה החדשה תושלם.
- באפליקציית האינטרנט, בוחרים באפשרות
> הוספת מסעדות לדוגמה. אם פונקציית הצילום שלכם מיושמת בצורה נכונה, המסעדות יופיעו בזמן אמת בלי שתרעננו את הדף.
8. שמירת ביקורות שנשלחו על ידי משתמשים מאפליקציית האינטרנט
- בקובץ
src/lib/firebase/firestore.js
, מחליפים את הפונקציהupdateWithRating()
בקוד הבא:
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()),
});
};
הקוד הזה מוסיף מסמך חדש ב-Firestore שמייצג את הביקורת החדשה. הקוד גם מעדכן את מסמך Firestore הקיים שמייצג את המסעדה, עם נתונים מעודכנים של מספר הדירוגים והדירוג הממוצע המחושב.
- מחליפים את הפונקציה
addReviewToRestaurant()
בקוד הבא:
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
פעולת שרת ב-Next.js מספקת API נוח לגישה לנתוני טופס, כמו data.get("text")
כדי לקבל את ערך הטקסט ממטען הייעודי (payload) של שליחת הטופס.
כדי להשתמש ב-Next.js Server Action לעיבוד הטופס לשליחת ביקורת, פועלים לפי השלבים הבאים:
- בקובץ
src/components/ReviewDialog.jsx
, מחפשים את המאפייןaction
ברכיב<form>
.
<form action={handleReviewFormSubmission}>
ערך המאפיין action
מתייחס לפונקציה שמטמיעים בשלב הבא.
- בקובץ
src/app/actions.js
, מחליפים את הפונקציהhandleReviewFormSubmission()
בקוד הבא:
// 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"),
});
}
הוספת ביקורות על מסעדה
הטמעתם תמיכה בשליחת ביקורות, ועכשיו אתם יכולים לוודא שהביקורות מוכנסות ל-Cloud Firestore בצורה נכונה.
כדי להוסיף ביקורת ולוודא שהיא מוכנסת ל-Cloud Firestore, פועלים לפי השלבים הבאים:
- יוצרים קומיט עם הודעת הקומיט 'Allow users to submit restaurant reviews' (מאפשרים למשתמשים לשלוח ביקורות על מסעדות) ומבצעים push למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase ומחכים עד שההשקה החדשה תושלם.
- מרעננים את אפליקציית האינטרנט ובוחרים מסעדה מדף הבית.
- בדף של המסעדה, לוחצים על הסמל
.
- בוחרים דירוג כוכבים.
- כתיבת ביקורת.
- לוחצים על שליחה. הביקורת שלכם תופיע בראש רשימת הביקורות.
- ב-Cloud Firestore, מחפשים בחלונית Add document את המסמך של המסעדה שכתבתם עליה ביקורת ובוחרים אותו.
- בחלונית התחלת איסוף, בוחרים באפשרות סיווגים.
- בחלונית Add document (הוספת מסמך), מחפשים את המסמך שרוצים לבדוק כדי לוודא שהוא הוכנס כמו שצריך.
9. שמירת קבצים שהמשתמשים העלו מאפליקציית האינטרנט
בקטע הזה, מוסיפים פונקציונליות שתאפשר להחליף את התמונה שמשויכת למסעדה כשמחוברים לחשבון. מעלים את התמונה ל-Firebase Storage ומעדכנים את כתובת ה-URL של התמונה במסמך Cloud Firestore שמייצג את המסעדה.
כדי לשמור קבצים שהמשתמשים העלו מאפליקציית האינטרנט, פועלים לפי השלבים הבאים:
- בקובץ
src/components/Restaurant.jsx
, בודקים את הקוד שמופעל כשהמשתמש מעלה קובץ:
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 });
}
לא צריך לבצע שינויים בפונקציה הזו, אבל בשלבים הבאים מוסבר איך מטמיעים את ההתנהגות של הפונקציה updateRestaurantImage()
.
- בקובץ
src/lib/firebase/storage.js
, מחליפים את הפונקציותupdateRestaurantImage()
ו-uploadImage()
בקוד הבא:
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);
}
הפונקציה updateRestaurantImageReference()
כבר מיושמת בשבילכם. הפונקציה הזו מעדכנת מסמך קיים של מסעדה ב-Cloud Firestore באמצעות כתובת URL מעודכנת של תמונה.
אימות הפונקציונליות של העלאת תמונות
כדי לוודא שהתמונה מועלית כצפוי, פועלים לפי השלבים הבאים:
- יוצרים קומיט עם הודעת הקומיט 'Allow users to change each restaurants' photo' (מאפשרים למשתמשים לשנות את התמונה של כל מסעדה) ומבצעים push למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase ומחכים עד שההשקה החדשה תושלם.
- באפליקציית האינטרנט, מוודאים שאתם מחוברים לחשבון ובוחרים מסעדה.
- לוחצים על
ומעלים תמונה ממערכת הקבצים. התמונה יוצאת מהסביבה המקומית ומועלית ל-Cloud Storage. התמונה מופיעה מיד אחרי שמעלים אותה.
- עוברים אל Cloud Storage for Firebase.
- עוברים לתיקייה שמייצגת את המסעדה. התמונה שהעליתם קיימת בתיקייה.
10. סיכום ביקורות על מסעדות באמצעות AI גנרטיבי
בקטע הזה תוסיפו תכונה של סיכום ביקורות, כדי שמשתמש יוכל להבין במהירות מה כולם חושבים על מסעדה מסוימת בלי לקרוא את כל הביקורות.
אחסון מפתח Gemini API ב-Cloud Secret Manager
- כדי להשתמש ב-Gemini API, תצטרכו מפתח API. עוברים אל Google AI Studio ולוחצים על 'יצירת מפתח API'.
- בשדה הקלט 'חיפוש פרויקטים ב-Google Cloud', בוחרים את פרויקט Firebase. כל פרויקט Firebase מגובה על ידי פרויקט Google Cloud.
- שירות App Hosting משולב עם Cloud Secret Manager כדי לאפשר לכם לאחסן ערכים רגישים כמו מפתחות API בצורה מאובטחת:
- בטרמינל, מריצים את הפקודה ליצירת סוד חדש:
firebase apphosting:secrets:set GEMINI_API_KEY
- כשמוצגת בקשה להזנת ערך הסוד, מעתיקים את מפתח Gemini API מ-Google AI Studio ומדביקים אותו.
- כשנשאלים אם הסוד החדש מיועד לסביבת הייצור או לבדיקה מקומית, בוחרים באפשרות 'סביבת ייצור'.
- כשמתבקשים לאשר גישה כדי שחשבון השירות של ה-backend יוכל לגשת לסוד, בוחרים באפשרות 'כן'.
- כשמוצגת השאלה אם להוסיף את הסוד החדש אל
apphosting.yaml
, מזיניםY
כדי לאשר.
מפתח Gemini API מאוחסן עכשיו בצורה מאובטחת ב-Cloud Secret Manager, ויש לו גישה לקצה העורפי של App Hosting.
הטמעה של רכיב סיכום הביקורות
- ב-
src/components/Reviews/ReviewSummary.jsx
, מחליפים את הפונקציהGeminiSummary
בקוד הבא: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>; } }
- יוצרים קומיט עם הודעת הקומיט 'שימוש ב-AI לסיכום ביקורות' ומבצעים push למאגר GitHub.
- פותחים את הדף App Hosting במסוף Firebase ומחכים עד שההשקה החדשה תושלם.
- פותחים דף של מסעדה. למעלה אמור להופיע סיכום של כל הביקורות בדף במשפט אחד.
- מוסיפים ביקורת חדשה ומרעננים את הדף. סיכום השינוי אמור להופיע.
11. סיכום
כל הכבוד! למדתם איך להשתמש ב-Firebase כדי להוסיף תכונות ופונקציונליות לאפליקציית Next.js. בפרט, השתמשתם ברכיבים הבאים:
- Firebase App Hosting כדי ליצור ולפרוס באופן אוטומטי את קוד Next.js בכל פעם שמעלים קוד לענף מוגדר.
- אימות ב-Firebase כדי להפעיל את הפונקציונליות של כניסה ויציאה.
- Cloud Firestore לנתוני מסעדות ולנתוני ביקורות על מסעדות.
- Cloud Storage for Firebase לתמונות של מסעדות.