1. לפני שמתחילים
בקודלאב הזה תלמדו איך לשלב את Firebase עם אפליקציית אינטרנט של Next.js שנקראת Friendly Eats, שהיא אתר לביקורות על מסעדות.
אפליקציית האינטרנט שהושלמה כוללת תכונות שימושיות שמדגימות איך פלטפורמת Firebase יכולה לעזור לכם לבנות אפליקציות של Next.js. התכונות האלה כוללות:
- פיתוח ופריסה אוטומטיים: ה-Codelab הזה משתמש באירוח אפליקציות ב-Firebase כדי ליצור ולפרוס באופן אוטומטי את קוד Next.js בכל פעם שאתם דוחפים להסתעפות שהוגדרה.
- כניסה ויציאה: אפליקציית האינטרנט שהושלמה מאפשרת להיכנס באמצעות חשבון Google ולצאת מהחשבון. ההתחברות והעקביות של המשתמשים מנוהלות רק באמצעות האימות ב-Firebase.
- תמונות: אפליקציית האינטרנט המושלמת מאפשרת למשתמשים שמחוברים להעלות תמונות של המסעדה. נכסי התמונות נשמרים ב-Cloud Storage for Firebase. ה-SDK של JavaScript ב-Firebase מספק כתובת 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
בקודלאב הזה נספק את קוד המקור הבסיסי של האפליקציה, והוא מבוסס על Firebase CLI.
יצירת מאגר ב-GitHub
אפשר למצוא את מקור ה-Codelab בכתובת https://github.com/firebase/assistanteats-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 commit -a -m "codelab starting point" git branch -M main
- יוצרים מאגר חדש ב-GitHub: https://github.com/new. נותנים לו שם כלשהו.
- ב-GitHub תקבלו כתובת URL חדשה של המאגר שנראית כך:
https://github.com/
או/ .git git@github.com:
. העתקת כתובת ה-URL הזו./ .git
- ב-GitHub תקבלו כתובת URL חדשה של המאגר שנראית כך:
- מעבירים את השינויים המקומיים למאגר החדש ב-GitHub. מריצים את הפקודה הבאה, ומחליפים את placeholder
בכתובת ה-URL של המאגר.git remote add origin <your-repository-url> git push -u origin main
- עכשיו קוד ההתחלה אמור להופיע במאגר שלכם ב-GitHub.
מתקינים או מעדכנים את ה-CLI של Firebase
מריצים את הפקודה הבאה כדי לוודא ש-Firebase CLI מותקן ושהגרסה שלו היא 13.9.0 ואילך:
firebase --version
אם מוצגת גרסה ישנה יותר או אם Firebase CLI לא מותקן, מריצים את פקודת ההתקנה:
npm install -g firebase-tools@latest
אם אתם לא מצליחים להתקין את ה-CLI של Firebase בגלל שגיאות הרשאה, כדאי לעיין במסמכי התיעוד של NPM או להשתמש באפשרות התקנה אחרת.
התחברות ל-Firebase
- מריצים את הפקודה הבאה כדי להתחבר ל-CLI של Firebase:
firebase login
- מזינים
Y
אוN
אם רוצים שמערכת Firebase תאסוף נתונים. - בדפדפן, בוחרים את חשבון Google ולוחצים על אישור.
3. הגדרת פרויקט Firebase
בקטע הזה צריך להגדיר פרויקט Firebase ולשייך אליו אפליקציית אינטרנט של Firebase. בנוסף, תגדירו את שירותי Firebase שבהם משתמשת אפליקציית האינטרנט לדוגמה.
יצירת פרויקט Firebase
- במסוף Firebase, לוחצים על Add project (הוספת פרויקט).
- בתיבת הטקסט Enter your project name, מזינים
FriendlyEats Codelab
(או שם של פרויקט לבחירתכם) ולוחצים על Continue. - בחלון אישור תוכנית החיוב ב-Firebase, מוודאים שהתוכנית היא Blaze, ואז לוחצים על Confirm plan (אישור התוכנית).
- כדי להשתמש ב-Codelab הזה אין צורך ב-Google Analytics, לכן מעבירים את האפשרות הפעלת Google Analytics לפרויקט הזה למצב מושבת.
- לוחצים על Create project.
- ממתינים עד להקצאת הפרויקט ולאחר מכן לוחצים על המשך.
- בפרויקט Firebase, עוברים אל Project Settings (הגדרות הפרויקט). חשוב לזכור את מזהה הפרויקט כי תצטרכו אותו בהמשך. המזהה הייחודי הזה משמש לזיהוי הפרויקט (לדוגמה, ב-CLI של Firebase).
שדרוג תוכנית התמחור והתשלומים ב-Firebase
כדי להשתמש באירוח אפליקציות ב-Firebase וב-Cloud Storage for Firebase, הפרויקט ב-Firebase צריך להיות מוגדר לתוכנית תמחור ותשלומים לפי שימוש (Blaze). כלומר, הפרויקט מקושר לחשבון לחיוב ב-Cloud.
- בחשבון לחיוב ב-Cloud נדרש אמצעי תשלום, כמו כרטיס אשראי.
- משתמשים חדשים ב-Firebase וב-Google Cloud? תוכלו לבדוק אם אתם זכאים לזיכוי בסך 300$ולחשבון לחיוב ב-Cloud לתקופת ניסיון בחינם.
- אם אתם מבצעים את הקודלאב הזה כחלק מאירוע, כדאי לשאול את המארגן אם יש זיכויים ב-Cloud שזמינים.
כדי לשדרג את הפרויקט לתוכנית Blaze:
- במסוף Firebase, בוחרים באפשרות שדרוג התוכנית.
- בוחרים את התוכנית Blaze. פועלים לפי ההוראות במסך כדי לקשר חשבון לחיוב ב-Cloud לפרויקט.
אם הייתם צריכים ליצור חשבון לחיוב ב-Cloud כחלק מהשדרוג הזה, ייתכן שתצטרכו לחזור לתהליך השדרוג במסוף Firebase כדי להשלים את השדרוג.
הוספה של אפליקציית אינטרנט לפרויקט Firebase
- עוברים אל סקירה כללית של הפרויקט בפרויקט Firebase, ואז לוחצים על אינטרנט.
אם כבר יש לכם אפליקציות רשומות בפרויקט, לוחצים על הוספת אפליקציה כדי להציג את סמל האינטרנט. - בתיבת הטקסט כינוי האפליקציה, מזינים כינוי לאפליקציה שקל לזכור, כמו
My Next.js app
. - לא מסמנים את התיבה Also set up Firebase Hosting for this app (גם להגדיר אירוח ב-Firebase לאפליקציה הזו).
- לוחצים על Register app (רישום האפליקציה) > Next (הבא) > Next (הבא) > Continue to console (המשך למסוף).
הגדרת שירותי Firebase במסוף Firebase
הגדרת אימות
- במסוף Firebase, עוברים אל Authentication.
- לוחצים על תחילת העבודה.
- בעמודה ספקים נוספים, לוחצים על Google > הפעלה.
- בתיבת הטקסט Public name for project, מזינים שם שקל לזכור, כמו
My Next.js app
. - בתפריט הנפתח Support email for project, בוחרים את כתובת האימייל שלכם.
- לוחצים על שמירה.
הגדרת Cloud Firestore
- בחלונית הימנית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Firestore database.
- לוחצים על Create database.
- משאירים את הערך
(default)
בשדה Database ID. - בוחרים מיקום למסד הנתונים ולוחצים על הבא.
באפליקציה אמיתית, כדאי לבחור מיקום קרוב למשתמשים. - לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור לגבי כללי האבטחה.
בהמשך הסדנה תוסיפו כללי אבטחה כדי לאבטח את הנתונים. לא תפיץ או תחשוף אפליקציה באופן ציבורי, בלי להוסיף כללי אבטחה למסד הנתונים שלכם. - לוחצים על יצירה.
הגדרה של Cloud Storage for Firebase
- בחלונית השמאלית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Storage (אחסון).
- לוחצים על תחילת העבודה.
- יש לבחור מיקום לקטגוריית האחסון המוגדרת כברירת מחדל.
קטגוריות ב-US-WEST1
, ב-US-CENTRAL1
וב-US-EAST1
יכולות לנצל את המסלול 'חינם תמיד' ל-Google Cloud Storage. קטגוריות בכל המיקומים האחרים כפופות לתמחור ולשימוש ב-Google Cloud Storage. - לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור לגבי כללי האבטחה.
בהמשך הסדנה תוסיפו כללי אבטחה כדי לאבטח את הנתונים. לא תפיץ או תחשוף אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה לקטגוריית האחסון שלכם. - לוחצים על יצירה.
4. בדיקת ה-codebase למתחילים
בקטע הזה נבדוק כמה תחומים בקוד הבסיסי של האפליקציה, שאליהם נוסיף פונקציונליות במהלך הקודלאב.
מבנה התיקיות והקבצים
בטבלה הבאה מופיעה סקירה כללית של מבנה התיקיות והקבצים באפליקציה:
תיקיות וקבצים | תיאור |
| רכיבי React למסננים, לכותרות, לפרטי מסעדות ולביקורות |
| פונקציות שירות שלא בהכרח קשורות ל-React או ל-Next.js |
| קוד ותצורה ספציפיים ל-Firebase |
| נכסים סטטיים באפליקציית האינטרנט, כמו סמלים |
| ניתוב באמצעות נתב האפליקציה Next.js |
| טיפול במסלול API |
| יחסי תלות בפרויקט באמצעות npm |
| הגדרה ספציפית ל-Next.js (פעולות השרת מופעלות) |
| הגדרה של שירות השפה ב-JavaScript |
רכיבי שרת ולקוח
האפליקציה היא אפליקציית אינטרנט של Next.js שמשתמשת ב-App Router. רינדור השרת מתבצע בכל חלקי האפליקציה. לדוגמה, הקובץ 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.
עד סוף הקטע הזה, יהיה לכם קצה עורפי של אירוח אפליקציות שמחובר למאגר שלכם ב-GitHub. השירות יבנה מחדש ותשיק באופן אוטומטי גרסה חדשה של האפליקציה שלכם בכל פעם שתוסיפו התחייבות חדשה להסתעפות main
שלכם.
פריסה של כללי אבטחה
הקוד כבר מכיל קבוצות של כללי אבטחה ל-Firestore ול-Cloud Storage for Firebase. אחרי הפריסה של כללי האבטחה, הנתונים במסד הנתונים ובקטגוריה מוגנים טוב יותר מפני שימוש לרעה.
- בטרמינל, מגדירים את ה-CLI לשימוש בפרויקט Firebase שיצרתם קודם:
כשמוצגת בקשה להזנת כינוי, מזיניםfirebase use --add
friendlyeats-codelab
. - כדי לפרוס את כללי האבטחה האלה, מריצים את הפקודה הבאה בטרמינל:
firebase deploy --only firestore:rules,storage
- אם תופיע השאלה:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, אפשר להקיש עלEnter
כדי לבחור באפשרות כן.
הוספת ההגדרה של Firebase לקוד של אפליקציית האינטרנט
- במסוף Firebase, נכנסים לקטע Project settings (הגדרות הפרויקט).
- בחלונית הגדרה ותצורה של SDK, לוחצים על 'הוספת אפליקציה' ואז על סמל סוגרי הקוד
כדי לרשום אפליקציית אינטרנט חדשה.
- בסוף תהליך היצירה של אפליקציית האינטרנט, מעתיקים את המשתנה
firebaseConfig
ואת המאפיינים שלו ואת הערכים שלהם. - פותחים את הקובץ
apphosting.yaml
בעורך הקוד וממלאים את הערכים של משתני הסביבה בערכי ההגדרות האישיות ממסוף Firebase. - בקובץ, מחליפים את המאפיינים הקיימים באלה שהעתקתם.
- שומרים את הקובץ.
יצירת קצה עורפי
- נכנסים אל הדף 'אירוח אפליקציות' במסוף Firebase:
- לוחצים על 'תחילת העבודה' כדי להתחיל בתהליך היצירה של הקצה העורפי. מגדירים את הקצה העורפי באופן הבא:
- פועלים לפי ההנחיות בשלב הראשון כדי לחבר את מאגר GitHub שיצרתם קודם.
- קובעים את הגדרות הפריסה:
- השארת ספריית השורש כ-
/
- הגדרת ההסתעפות הפעילה כ-
main
- הפעלת השקות אוטומטיות
- השארת ספריית השורש כ-
- נותנים שם לקצה העורפי
friendlyeats-codelab
. - בקטע 'יצירה או שיוך של אפליקציית אינטרנט ב-Firebase', בוחרים את אפליקציית האינטרנט שהגדרתם מקודם בתפריט הנפתח 'בחירת אפליקציית אינטרנט קיימת ב-Firebase'.
- לוחצים על 'סיום ופריסה'. אחרי רגע תועברו לדף חדש שבו ניתן לראות את הסטטוס של הקצה העורפי החדש לאירוח אפליקציות!
- בסיום ההשקה, לוחצים על הדומיין החינמי בקטע 'דומיינים'. יכול להיות שיחלפו כמה דקות עד שהשינוי יתחיל לפעול בגלל הפצת ה-DNS.
פרסת את אפליקציית האינטרנט הראשונית! בכל פעם שתוסיפו מחויבות חדשה להסתעפות main
של המאגר ב-GitHub, תראו התחלה של build חדש והשקה חדשה במסוף Firebase, והאתר יתעדכן באופן אוטומטי בסיום ההשקה.
6. הוספת אימות לאפליקציית האינטרנט
בקטע הזה מוסיפים אימות לאפליקציית האינטרנט כדי שתוכלו להתחבר אליה.
הטמעת פונקציות הכניסה והיציאה
- בקובץ
src/lib/firebase/auth.js
, מחליפים את הפונקציותonAuthStateChanged
,signInWithGoogle
ו-signOut
בקוד הבא:
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);
}
}
הקוד הזה משתמש בממשקי ה-API הבאים של Firebase:
Firebase API | תיאור |
יצירת מכונה של ספק אימות של Google. | |
הפעלת תהליך אימות מבוסס-דיאלוג. | |
יציאה מהחשבון של המשתמש. |
בקובץ src/components/Header.jsx
, הקוד כבר מפעיל את הפונקציות signInWithGoogle
ו-signOut
.
- יוצרים השמירה עם הודעת השמירה 'הוספת אימות Google' ומעבירים אותה למאגר ב-GitHub. 1. פותחים את הדף App Hosting במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- באפליקציית האינטרנט, מרעננים את הדף ולוחצים על כניסה באמצעות חשבון Google. אפליקציית האינטרנט לא מתעדכנת, ולכן לא ברור אם הכניסה בוצעה בהצלחה.
שליחת מצב האימות לשרת
כדי להעביר את מצב האימות לשרת, נשתמש ב-service worker. מחליפים את הפונקציות fetchWithFirebaseHeaders
ו-getAuthIdToken
בקוד הבא:
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);
}
קריאת מצב האימות בשרת
אנחנו נשתמש ב-FirebaseServerApp כדי לשקף את מצב האימות של הלקוח בשרת.
פותחים את src/lib/firebase/serverApp.js
ומחליפים את הפונקציה 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 };
}
הרשמה לעדכונים בנושא אימות
כדי להירשם לקבלת עדכונים על שינויים באימות:
- עוברים לקובץ
src/components/Header.jsx
. - מחליפים את הפונקציה
useUserSession
בקוד הבא:
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;
}
הקוד הזה משתמש ב-hook של מצב ב-React כדי לעדכן את המשתמש כשהפונקציה onAuthStateChanged
מציינת שיש שינוי במצב האימות.
אימות השינויים
פריסת הבסיס בקובץ src/app/layout.js
מרינדרת את הכותרת ומעבירה את המשתמש, אם הוא זמין, כפרמטר.
<Header initialUser={currentUser?.toJSON()} />
המשמעות היא שהרכיב <Header>
יוצר עיבוד של נתוני משתמשים, אם הם זמינים, במהלך זמן הריצה של השרת. אם יש עדכוני אימות במהלך מחזור החיים של הדף אחרי טעינת הדף הראשונית, ה-handler של onAuthStateChanged
מטפל בהם.
עכשיו הגיע הזמן להשיק build חדש ולאמת את מה שיצרת.
- יוצרים פעולת התחייבות עם ההודעה "Show signin state" (הצגת מצב הכניסה לחשבון) ומעבירים אותה למאגר שלכם ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- מוודאים את התנהגות האימות החדשה:
- מרעננים את אפליקציית האינטרנט בדפדפן. שם התצוגה מופיע בכותרת.
- יוצאים מהחשבון ונכנסים אליו שוב. הדף מתעדכן בזמן אמת בלי לרענן את הדף. אפשר לחזור על השלב הזה עם משתמשים שונים.
- אם רוצים, לוחצים לחיצה ימנית על אפליקציית האינטרנט, בוחרים באפשרות הצגת מקור הדף ומחפשים את השם המוצג. התג מופיע במקור ה-HTML הגולמי שמוחזר מהשרת.
7. הצגת פרטי המסעדה
אפליקציית האינטרנט כוללת נתוני הדמייה של מסעדות וביקורות.
הוספה של מסעדה אחת או יותר
כדי להוסיף נתונים של מסעדה מדומה למסד הנתונים המקומי ב-Cloud Firestore, צריך לבצע את השלבים הבאים:
- באפליקציית האינטרנט, בוחרים באפשרות > הוספת מסעדות לדוגמה.
- במסוף Firebase בדף Firestore Database, בוחרים באפשרות מסעדות. באוסף המסעדה מוצגים המסמכים ברמה העליונה, שכל אחד מהם מייצג מסעדה.
- לוחצים על כמה מסמכים כדי לעיין במאפיינים של מסמך של מסעדה.
הצגת רשימת המסעדות
במסד הנתונים של 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(),
};
});
}
- יוצרים השמירה עם הודעת השמירה 'קריאת רשימת המסעדות מ-Firestore' ומעבירים אותה למאגר ב-GitHub.
- פותחים את הדף 'אירוח אפליקציות' במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- באפליקציית האינטרנט, מרעננים את הדף. תמונות של מסעדות מופיעות כמשבצות בדף.
יש לוודא שדפי העסק של המסעדות נטענים בזמן ההפעלה של השרת
באמצעות ה-framework של Next.js, ייתכן שלא יהיה ברור מתי הנתונים נטענים בזמן הריצה של השרת או בזמן הריצה בצד הלקוח.
כדי לוודא שרשימות של מסעדות נטענים בזמן ההפעלה של השרת, פועלים לפי השלבים הבאים:
- באפליקציית האינטרנט, פותחים את DevTools ומשביתים את 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(() => {
const unsubscribe = getRestaurantsSnapshot(data => {
setRestaurants(data);
}, filters);
return () => {
unsubscribe();
};
}, [filters]);
הקוד הזה מפעיל את הפונקציה getRestaurantsSnapshot()
, שדומה לפונקציה getRestaurants()
שהטמעתם בשלב קודם. עם זאת, פונקציית ה-snapshot מספקת מנגנון קריאה חוזרת (callback) כדי שהיא תופעל בכל פעם שמתבצע שינוי באוסף של המסעדה.
- בקובץ
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);
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;
}
שינויים שבוצעו דרך הדף Firestore Database יופיעו עכשיו בזמן אמת באפליקציית האינטרנט.
- יוצרים השמירה עם הודעת השמירה Listen for realtime restaurant updates (האזנה לעדכונים בזמן אמת על מסעדות) ומעבירים אותה למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- באפליקציית האינטרנט, בוחרים באפשרות > הוספת מסעדות לדוגמה. אם הפונקציה של קובץ ה-snapshot מוטמעת בצורה נכונה, המסעדות יופיעו בזמן אמת בלי צורך לרענן את הדף.
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 כדי לעבד את שליחת טופס הבדיקה, מבצעים את השלבים הבאים:
- בקובץ
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' (מתן אפשרות למשתמשים לשלוח ביקורות על מסעדות) ומעבירים אותה למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- מרעננים את אפליקציית האינטרנט ובוחרים מסעדה מדף הבית.
- בדף המסעדה, לוחצים על .
- בוחרים דירוג כוכבים.
- לכתוב ביקורת.
- לוחצים על שליחה. הביקורת תופיע בראש רשימת הביקורות.
- ב-Cloud Firestore, מחפשים את המסמך של המסעדה שבדקתם בחלונית Add document ובוחרים אותו.
- בחלונית Start collection, לוחצים על ratings.
- בחלונית 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);
setRestaurant({ ...restaurant, 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' (מתן אפשרות למשתמשים לשנות את התמונה של כל מסעדה) ומעבירים אותה למאגר ב-GitHub.
- פותחים את הדף App Hosting במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- באפליקציית האינטרנט, מוודאים שהתחברתם לחשבון ובוחרים מסעדה.
- לוחצים על ומעלים תמונה ממערכת הקבצים. התמונה נשלחת מהסביבה המקומית ומועלה ל-Cloud Storage. התמונה תופיע מיד אחרי שתעלו אותה.
- עוברים אל Cloud Storage ב-Firebase.
- עוברים לתיקייה שמייצגת את המסעדה. התמונה שהעליתם קיימת בתיקייה.
10. סיכום של ביקורות על מסעדות באמצעות AI גנרטיבי
בקטע הזה תוסיפו תכונה של סיכום ביקורות, כדי שמשתמש יוכל להבין במהירות מה כולם חושבים על מסעדה, בלי שיצטרך לקרוא את כל הביקורות.
אחסון מפתח ל-Gemini API ב-Cloud Secret Manager
- כדי להשתמש ב-Gemini API, אתם צריכים מפתח API. יצירת מפתח ב-Google AI Studio
- אירוח אפליקציות משתלב עם Cloud Secret Manager כדי לאפשר לכם לאחסן ערכים רגישים כגון מפתחות API באופן מאובטח:
- בטרמינל, מריצים את הפקודה הבאה כדי ליצור סוד חדש:
firebase apphosting:secrets:set gemini-api-key
- כשמתבקשים להזין את הערך הסודי, מעתיקים ומדביקים את מפתח Gemini API מ-Google AI Studio.
- כשמוצגת השאלה אם להוסיף את הסוד החדש אל
apphosting.yaml
, כותביםY
כדי לאשר.
מפתח ה-API של Gemini מאוחסן עכשיו באופן מאובטח ב-Cloud Secret Manager, ויש לו גישה לקצה העורפי של אירוח האפליקציות.
הטמעת הרכיב 'סיכום ביקורות'
- ב-
src/components/Reviews/ReviewSummary.jsx
, מחליפים את הפונקציהGeminiSummary
בקוד הבא: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>; } }
- יוצרים השמירה עם הודעת השמירה 'שימוש ב-AI כדי לסכם ביקורות' ומעבירים אותה למאגר ב-GitHub.
- פותחים את הדף 'אירוח אפליקציות' במסוף Firebase וממתינים להשלמת ההשקה החדשה.
- פותחים דף של מסעדה. בחלק העליון של הדף, אמור להופיע סיכום של כל הביקורות בדף.
- מוסיפים ביקורת חדשה ומרעננים את הדף. הסיכום אמור להשתנות.
11. סיכום
כל הכבוד! למדתם איך להשתמש ב-Firebase כדי להוסיף תכונות ופונקציונליות לאפליקציית Next.js. באופן ספציפי, השתמשתם בפריטים הבאים:
- אירוח אפליקציות ב-Firebase – יצירה ופריסה אוטומטית של קוד Next.js בכל פעם שאתם דוחפים להסתעפות מוגדרת.
- אימות ב-Firebase כדי להפעיל את הפונקציונליות של הכניסה והיציאה.
- Cloud Firestore לנתוני מסעדות ולנתוני ביקורות על מסעדות.
- Cloud Storage for Firebase לתמונות של מסעדות.