1. قبل از شروع
در این کد لبه، یاد خواهید گرفت که چگونه Firebase را با یک برنامه وب Next.js به نام Friendly Eats که یک وب سایت برای بررسی رستوران ها است، ادغام کنید.
برنامه وب تکمیل شده ویژگی های مفیدی را ارائه می دهد که نشان می دهد Firebase چگونه می تواند به شما در ساخت برنامه های Next.js کمک کند. این ویژگی ها شامل موارد زیر است:
- ساخت و استقرار خودکار: این کد لبه از میزبانی برنامه Firebase برای ساخت و استقرار خودکار کد Next.js شما هر بار که به یک شاخه پیکربندی شده فشار میدهید، استفاده میکند.
- ورود و خروج: برنامه وب تکمیل شده به شما امکان می دهد با Google وارد شوید و از سیستم خارج شوید. ورود و تداوم کاربر به طور کامل از طریق Firebase Authentication مدیریت می شود.
- تصاویر: برنامه وب تکمیل شده به کاربرانی که وارد سیستم شده اند اجازه می دهد تصاویر رستوران را آپلود کنند. دارایی های تصویر در Cloud Storage برای Firebase ذخیره می شوند. Firebase JavaScript SDK یک URL عمومی برای تصاویر آپلود شده فراهم می کند. سپس این URL عمومی در سند رستوران مربوطه در Cloud Firestore ذخیره میشود.
- نظرات: برنامه وب تکمیلشده به کاربرانی که وارد سیستم شدهاند اجازه میدهد نظرات رستورانهایی را که شامل رتبهبندی ستاره و پیام متنی هستند، ارسال کنند. اطلاعات مرور در Cloud Firestore ذخیره می شود.
- فیلترها: برنامه وب تکمیلشده به کاربرانی که وارد سیستم شدهاند اجازه میدهد فهرست رستورانها را بر اساس دسته، مکان و قیمت فیلتر کنند. همچنین می توانید روش مرتب سازی مورد استفاده را سفارشی کنید. داده ها از Cloud Firestore قابل دسترسی هستند و پرس و جوهای Firestore بر اساس فیلترهای استفاده شده اعمال می شوند.
پیش نیازها
- یک حساب GitHub
- آشنایی با Next.js و جاوا اسکریپت
چیزی که یاد خواهید گرفت
- نحوه استفاده از Firebase با روتر برنامه Next.js و رندر سمت سرور.
- نحوه ماندگاری تصاویر در Cloud Storage برای Firebase.
- نحوه خواندن و نوشتن داده ها در پایگاه داده Cloud Firestore.
- نحوه استفاده از ورود به سیستم با Google با Firebase JavaScript SDK.
آنچه شما نیاز دارید
- Git
- نسخه پایدار اخیر Node.js
- مرورگر دلخواه شما، مانند گوگل کروم
- یک محیط توسعه با ویرایشگر کد و ترمینال
- یک حساب Google برای ایجاد و مدیریت پروژه Firebase شما
- توانایی ارتقاء پروژه Firebase خود به طرح قیمت گذاری Blaze
2. محیط توسعه و مخزن GitHub خود را راه اندازی کنید
این لبه کد پایه کد شروع برنامه را فراهم می کند و به Firebase CLI متکی است.
یک مخزن GitHub ایجاد کنید
منبع Codelab را می توان در https://github.com/firebase/friendlyeats-web یافت. این مخزن شامل پروژه های نمونه برای پلتفرم های متعدد است. با این حال، این کد لبه فقط از دایرکتوری 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
- از بسته giget npm برای واکشی فقط پوشه
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>
کنید.git remote add origin <REPOSITORY_URL> git push -u origin main
- اکنون باید کد شروع را در مخزن GitHub خود مشاهده کنید.
Firebase CLI را نصب یا بهروزرسانی کنید
برای تأیید اینکه Firebase CLI را نصب کرده اید و نسخه 14.1.0 یا بالاتر است، دستور زیر را اجرا کنید:
firebase --version
اگر نسخه پایینتری میبینید یا Firebase CLI را نصب نکردهاید، دستور install را اجرا کنید:
npm install -g firebase-tools@latest
اگر به دلیل خطاهای مجوز نمی توانید Firebase CLI را نصب کنید، اسناد npm را ببینید یا از گزینه نصب دیگری استفاده کنید.
وارد Firebase شوید
- برای ورود به Firebase CLI دستور زیر را اجرا کنید:
firebase login
- بسته به اینکه می خواهید Firebase داده ها را جمع آوری کند،
Y
یاN
را وارد کنید. - در مرورگر خود، حساب Google خود را انتخاب کنید و سپس روی Allow کلیک کنید.
3. پروژه Firebase خود را راه اندازی کنید
در این بخش، یک پروژه Firebase را راهاندازی کرده و یک برنامه وب Firebase را با آن مرتبط میکنید. همچنین سرویسهای Firebase را که توسط برنامه وب نمونه استفاده میشود، راهاندازی میکنید.
یک پروژه Firebase ایجاد کنید
- در کنسول Firebase ، روی افزودن پروژه کلیک کنید.
- در کادر متنی نام پروژه خود را وارد کنید ،
FriendlyEats Codelab
(یا نام پروژه دلخواهتان) را وارد کنید و سپس روی Continue کلیک کنید. - برای این کد لبه، شما نیازی به Google Analytics ندارید، بنابراین گزینه Enable Google Analytics for this project را غیرفعال کنید.
- روی ایجاد پروژه کلیک کنید.
- منتظر بمانید تا پروژه شما ارائه شود و سپس روی Continue کلیک کنید.
- در پروژه Firebase خود، به تنظیمات پروژه بروید. شناسه پروژه خود را یادداشت کنید زیرا بعداً به آن نیاز دارید. این شناسه منحصر به فرد نحوه شناسایی پروژه شما است (به عنوان مثال، در Firebase CLI).
طرح قیمت گذاری Firebase خود را ارتقا دهید
برای استفاده از میزبانی برنامه Firebase و فضای ذخیرهسازی ابری برای Firebase، پروژه Firebase شما باید در طرح قیمتگذاری (Blaze) باشد، به این معنی که به یک حساب صورتحساب Cloud مرتبط است.
- حساب Cloud Billing به یک روش پرداخت مانند کارت اعتباری نیاز دارد.
- اگر تازه وارد Firebase و Google Cloud هستید، بررسی کنید که آیا واجد شرایط دریافت اعتبار 300 دلاری و یک حساب آزمایشی رایگان Cloud Billing هستید یا خیر.
- اگر این نرمافزار کد را بهعنوان بخشی از یک رویداد انجام میدهید، از سازماندهنده خود بپرسید که آیا اعتبارات Cloud موجود است یا خیر.
برای ارتقای پروژه خود به پلن Blaze، مراحل زیر را دنبال کنید:
- در کنسول Firebase، برنامه خود را ارتقا دهید .
- طرح Blaze را انتخاب کنید. دستورالعمل های روی صفحه را دنبال کنید تا یک حساب Cloud Billing را به پروژه خود پیوند دهید.
اگر به عنوان بخشی از این ارتقاء نیاز به ایجاد یک حساب Cloud Billing داشتید، ممکن است لازم باشد برای تکمیل ارتقاء به جریان ارتقاء در کنسول Firebase برگردید.
یک برنامه وب به پروژه Firebase خود اضافه کنید
- در پروژه Firebase خود به نمای کلی پروژه خود بروید و سپس کلیک کنید
وب
اگر قبلاً برنامههایی را در پروژه خود ثبت کردهاید، روی افزودن برنامه کلیک کنید تا نماد وب را ببینید. - در کادر متنی نام مستعار برنامه ، یک نام مستعار برنامه به یاد ماندنی، مانند
My Next.js app
وارد کنید. - چک باکس همچنین تنظیم Firebase Hosting برای این برنامه را بدون علامت نگه دارید.
- روی ثبت برنامه > ادامه به کنسول کلیک کنید.
سرویس های Firebase را در کنسول Firebase تنظیم کنید
احراز هویت را تنظیم کنید
- در کنسول Firebase، به Authentication بروید.
- روی Get start کلیک کنید.
- در ستون ارائه دهندگان اضافی ، روی Google > فعال کردن کلیک کنید.
- در کادر متنی نام عمومی برای پروژه ، یک نام به یاد ماندنی مانند
My Next.js app
وارد کنید. - از ایمیل کشویی پشتیبانی برای پروژه ، آدرس ایمیل خود را انتخاب کنید.
- روی ذخیره کلیک کنید.
Cloud Firestore را راه اندازی کنید
- در پنل سمت چپ کنسول Firebase، Build را گسترش دهید و سپس Firestore Database را انتخاب کنید.
- روی ایجاد پایگاه داده کلیک کنید.
- شناسه پایگاه داده را روی
(default)
بگذارید. - یک مکان برای پایگاه داده خود انتخاب کنید، سپس روی Next کلیک کنید.
برای یک برنامه واقعی، می خواهید مکانی را انتخاب کنید که به کاربران شما نزدیک باشد. - در حالت تست روی Start کلیک کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید.
بعداً در این کد، قوانین امنیتی را برای ایمن سازی داده های خود اضافه خواهید کرد. بدون افزودن قوانین امنیتی برای پایگاه داده خود، یک برنامه را به صورت عمومی توزیع یا افشا نکنید . - روی ایجاد کلیک کنید.
Cloud Storage را برای Firebase تنظیم کنید
- در پانل سمت چپ کنسول Firebase، Build را گسترش دهید و سپس Storage را انتخاب کنید.
- روی Get start کلیک کنید.
- مکانی را برای سطل ذخیره سازی پیش فرض خود انتخاب کنید.
سطلها درUS-WEST1
،US-CENTRAL1
، وUS-EAST1
میتوانند از لایه «همیشه رایگان» برای Google Cloud Storage استفاده کنند. سطلها در همه مکانهای دیگر از قیمت و استفاده از Google Cloud Storage پیروی میکنند. - در حالت تست روی Start کلیک کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید.
بعداً در این کد، قوانین امنیتی را برای ایمن کردن دادههای خود اضافه خواهید کرد. بدون افزودن قوانین امنیتی برای سطل ذخیرهسازی خود، برنامهای را به صورت عمومی توزیع یا افشا نکنید . - روی ایجاد کلیک کنید.
استقرار قوانین امنیتی
این کد قبلاً دارای مجموعهای از قوانین امنیتی برای Firestore و برای Cloud Storage برای 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
فشار دهید تا Yes را انتخاب کنید.
4. پایگاه کد استارتر را مرور کنید
در این بخش، چند قسمت از پایگاه کد شروع برنامه را بررسی میکنید که عملکردی را در این لبه کد به آنها اضافه میکنید.
ساختار پوشه و فایل
جدول زیر شامل نمای کلی از پوشه و ساختار فایل برنامه است:
پوشه ها و فایل ها | توضیحات |
| برای فیلترها، سرصفحهها، جزئیات رستوران و نظرات، اجزای سازنده واکنش نشان دهید |
| توابع ابزاری که لزوماً به React یا Next.js مقید نیستند |
| کد مخصوص Firebase و پیکربندی Firebase |
| دارایی های ثابت در برنامه وب، مانند نمادها |
| مسیریابی با روتر برنامه Next.js |
| وابستگی های پروژه با npm |
| پیکربندی ویژه Next.js (عملکردهای سرور فعال هستند) |
| پیکربندی سرویس زبان جاوا اسکریپت |
اجزای سرور و مشتری
این برنامه یک برنامه وب 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. یک باطن میزبانی برنامه ایجاد کنید
در این بخش، یک App Hosting Backend را برای تماشای یک شعبه در مخزن git خود راه اندازی خواهید کرد.
در پایان این بخش، یک باطن میزبانی برنامه خواهید داشت که به مخزن خود در GitHub متصل است که هر زمان که یک commit جدید را به شعبه main
خود فشار دهید، به طور خودکار نسخه جدیدی از برنامه شما را بازسازی و عرضه می کند.
یک Backend ایجاد کنید
- به صفحه میزبانی برنامه در کنسول Firebase بروید:
- برای شروع جریان ایجاد backend روی «شروع به کار» کلیک کنید. باطن خود را به صورت زیر پیکربندی کنید:
- یک منطقه را انتخاب کنید. برای یک برنامه واقعی، نزدیک ترین منطقه به کاربران خود را انتخاب می کنید.
- برای اتصال مخزن GitHub که قبلا ایجاد کردهاید، دستورالعملهای مرحله «وارد کردن مخزن GitHub» را دنبال کنید.
- تنظیم تنظیمات استقرار:
- دایرکتوری ریشه را به صورت
/
نگه دارید - شاخه زنده را روی
main
قرار دهید - فعال کردن عرضه خودکار
- دایرکتوری ریشه را به صورت
- باطن خود را
friendlyeats-codelab
نام ببرید. - در «ارتباط با برنامه وب Firebase»، روی «ایجاد یک برنامه وب Firebase جدید» کلیک کنید.
- روی "Finish and Deploy" کلیک کنید. پس از مدتی، به صفحه جدیدی هدایت خواهید شد که در آن میتوانید وضعیت باطن میزبانی برنامه جدید خود را ببینید!
- پس از تکمیل عرضه، روی دامنه رایگان خود در زیر «دامنه ها» کلیک کنید. به دلیل انتشار DNS ممکن است چند دقیقه طول بکشد تا شروع به کار کند.
- اوه اوه هنگامی که صفحه را بارگیری می کنید، یک پیام خطایی خواهید دید که می گوید "خطای برنامه: یک استثنا در سمت سرور رخ داده است (برای اطلاعات بیشتر به گزارش های سرور مراجعه کنید)."
- در کنسول Firebase، برگه "Logs" بخش پشتیبان میزبانی برنامه خود را بررسی کنید. گزارش "خطا: اجرا نشد" را مشاهده خواهید کرد. وقتی احراز هویت را اضافه میکنیم، آن را در مرحله بعدی برطرف خواهیم کرد.
شما برنامه وب اولیه را مستقر کرده اید! هر بار که یک commit جدید را به شاخه main
مخزن GitHub خود فشار می دهید، می بینید که یک ساخت و عرضه جدید در کنسول Firebase شروع می شود و سایت شما به طور خودکار پس از تکمیل عرضه به روز می شود.
6. احراز هویت را به برنامه وب اضافه کنید
در این بخش، احراز هویت را به وب اپلیکیشن اضافه می کنید تا بتوانید وارد آن شوید.
یک دامنه مجاز اضافه کنید
Firebase Authentication فقط درخواستهای ورود از دامنههایی را میپذیرد که شما اجازه میدهید. در اینجا، دامنه پشتیبان میزبانی برنامه شما را به لیست دامنه های تایید شده در پروژه شما اضافه می کنیم.
- دامنه باطن میزبانی برنامه را از صفحه «نمای کلی» میزبانی برنامه کپی کنید.
- به برگه تنظیمات تأییدیه بروید و دامنه های مجاز را انتخاب کنید.
- روی دکمه افزودن دامنه کلیک کنید.
- دامنه باطن میزبانی برنامه خود را وارد کنید.
عملکردهای ورود و خروج را پیاده سازی کنید
- در فایل
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 | توضیحات |
یک ناظر برای تغییرات در وضعیت ورود به سیستم کاربر اضافه می کند. | |
یک ناظر برای تغییرات در شناسه شناسه کاربر اضافه می کند. | |
یک نمونه ارائه دهنده احراز هویت Google ایجاد می کند. | |
یک جریان احراز هویت مبتنی بر گفتگو را شروع می کند. | |
کاربر را از سیستم خارج می کند. |
در فایل src/components/Header.jsx
، کد از قبل توابع signInWithGoogle
و signOut
فراخوانی می کند.
وضعیت احراز هویت را به سرور ارسال کنید
برای انتقال وضعیت احراز هویت به سرور، از کوکی ها استفاده می کنیم. هر زمان که وضعیت احراز هویت در مشتری تغییر کند، کوکی __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>
دادههای کاربر را، در صورت وجود، در طول زمان اجرای سرور ارائه میکند. اگر در طول چرخه حیات صفحه پس از بارگیری اولیه صفحه، بهروزرسانیهایی برای احراز هویت وجود داشته باشد، کنترلکننده onAuthStateChanged
آنها را مدیریت میکند.
اکنون وقت آن است که یک بیلد جدید راه اندازی کنید و آنچه را که ساخته اید تأیید کنید.
- یک commit با پیام commit "Add authentication" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبانی برنامه را در کنسول Firebase باز کنید و منتظر بمانید تا عرضه جدید شما تکمیل شود.
- رفتار احراز هویت جدید را تأیید کنید:
- در مرورگر خود، برنامه وب را بازخوانی کنید. نام نمایشی شما در هدر ظاهر می شود.
- از سیستم خارج شوید و دوباره وارد شوید. می توانید این مرحله را با کاربران مختلف تکرار کنید.
- اختیاری: روی برنامه وب کلیک راست کنید، View page source را انتخاب کنید و نام نمایشی را جستجو کنید. در منبع HTML خام که از سرور بازگردانده شده است ظاهر می شود.
7. مشاهده اطلاعات رستوران
برنامه وب شامل داده های ساختگی برای رستوران ها و نظرات است.
یک یا چند رستوران اضافه کنید
برای درج داده های رستوران ساختگی در پایگاه داده محلی Cloud Firestore خود، این مراحل را دنبال کنید:
- اگر قبلاً وارد برنامه وب نشده اید، وارد برنامه وب شوید. سپس، انتخاب کنید
> رستوران های نمونه را اضافه کنید .
- در کنسول Firebase در صفحه پایگاه داده Firestore ، رستوران ها را انتخاب کنید. اسناد سطح بالا را در مجموعه رستوران مشاهده می کنید که هر کدام نشان دهنده یک رستوران هستند.
- برای بررسی ویژگیهای یک سند رستوران، روی چند سند کلیک کنید.
نمایش لیست رستوران ها
پایگاه داده 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(),
};
});
}
- یک commit با پیام commit "خواندن لیست رستوران ها از Firestore" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبانی برنامه را در کنسول Firebase باز کنید و منتظر بمانید تا عرضه جدید شما تکمیل شود.
- در برنامه وب، صفحه را بازخوانی کنید. تصاویر رستوران به صورت کاشی در صفحه ظاهر می شوند.
بررسی کنید که لیست رستوران ها در زمان اجرای سرور بارگیری می شوند
با استفاده از چارچوب Next.js، زمانی که داده ها در زمان اجرای سرور یا زمان اجرای سمت کلاینت بارگیری می شوند، ممکن است واضح نباشد.
برای تأیید بارگیری فهرستهای رستوران در زمان اجرای سرور، این مراحل را دنبال کنید:
- در برنامه وب، DevTools را باز کنید و جاوا اسکریپت را غیرفعال کنید .
- برنامه وب را بازخوانی کنید. لیست رستوران ها هنوز بار می شود. اطلاعات رستوران در پاسخ سرور برگردانده می شود. وقتی جاوا اسکریپت فعال است، اطلاعات رستوران از طریق کد جاوا اسکریپت سمت سرویس گیرنده هیدراته می شود.
- در DevTools، جاوا اسکریپت را دوباره فعال کنید .
با شنوندگان عکس فوری 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 اکنون در برنامه وب در زمان واقعی منعکس می شود.
- یک commit با پیام commit "Listen for realtime restaurant updates" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبانی برنامه را در کنسول 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 Server Action یک API مناسب برای دسترسی به دادههای فرم، مانند data.get("text")
برای دریافت مقدار متن از بار ارسال فرم ارائه میکند.
برای استفاده از 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 درج شده است، این مراحل را دنبال کنید:
- یک commit با پیام commit "اجازه به کاربران برای ارسال نظرات رستوران" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبانی برنامه را در کنسول Firebase باز کنید و منتظر بمانید تا عرضه جدید شما تکمیل شود.
- برنامه وب را بازخوانی کنید و یک رستوران را از صفحه اصلی انتخاب کنید.
- در صفحه رستوران کلیک کنید
.
- یک رتبه بندی ستاره انتخاب کنید.
- یک بررسی بنویسید.
- روی ارسال کلیک کنید. نظر شما در بالای لیست نظرات ظاهر می شود.
- در Cloud Firestore، در پنجره افزودن سند ، سند رستورانی را که بررسی کردهاید جستجو کنید و آن را انتخاب کنید.
- در صفحه مجموعه شروع ، رتبه بندی ها را انتخاب کنید.
- در صفحه افزودن سند ، سندی را برای بررسی خود پیدا کنید تا تأیید کنید که مطابق انتظار درج شده است.
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 تصویر به روز شده به روز می کند.
عملکرد آپلود تصویر را تأیید کنید
برای تأیید اینکه تصویر طبق انتظار آپلود می شود، این مراحل را دنبال کنید:
- یک commit با پیام commit "اجازه به کاربران برای تغییر عکس هر رستوران" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبانی برنامه را در کنسول Firebase باز کنید و منتظر بمانید تا عرضه جدید شما تکمیل شود.
- در برنامه وب، تأیید کنید که وارد سیستم شده اید و یک رستوران را انتخاب کنید.
- کلیک کنید
و یک تصویر از فایل سیستم خود آپلود کنید. تصویر شما از محیط محلی شما خارج می شود و در فضای ذخیره سازی ابری آپلود می شود. تصویر بلافاصله پس از آپلود ظاهر می شود.
- برای Firebase به Cloud Storage بروید.
- به پوشه ای که نشان دهنده رستوران است بروید. تصویری که آپلود کردید در پوشه وجود دارد.
10. نظرات رستوران را با مولد ai خلاصه کنید
در این بخش، ویژگی خلاصه بررسی را اضافه میکنید تا کاربر بتواند بدون نیاز به خواندن هر نظر، به سرعت بفهمد که همه درباره یک رستوران چه فکر میکنند.
یک کلید API Gemini را در Cloud Secret Manager ذخیره کنید
- برای استفاده از Gemini API، به یک کلید API نیاز دارید. به استودیوی هوش مصنوعی گوگل مراجعه کنید و روی «ایجاد کلید API» کلیک کنید.
- در ورودی «جستجوی پروژههای Google Cloud»، پروژه Firebase خود را انتخاب کنید. هر پروژه Firebase توسط یک پروژه Google Cloud پشتیبانی می شود.
- میزبانی برنامه با Cloud Secret Manager ادغام می شود تا به شما امکان می دهد مقادیر حساس مانند کلیدهای API را به صورت ایمن ذخیره کنید:
- در یک ترمینال، دستور ایجاد یک راز جدید را اجرا کنید:
firebase apphosting:secrets:set GEMINI_API_KEY
- هنگامی که مقدار مخفی از شما خواسته شد، کلید Gemini API خود را از Google AI Studio کپی و جایگذاری کنید.
- هنگامی که از شما پرسیده شد که آیا راز جدید برای تولید یا آزمایش محلی است، "تولید" را انتخاب کنید.
- وقتی از شما پرسیده شد که آیا میخواهید به آن دسترسی بدهید تا حساب سرویس پشتیبان شما بتواند به راز دسترسی پیدا کند، «بله» را انتخاب کنید.
- وقتی از شما پرسیده شد که آیا راز جدید باید به
apphosting.yaml
اضافه شود،Y
را وارد کنید تا بپذیرید.
کلید Gemini API شما اکنون به طور ایمن در مدیر Cloud Secret ذخیره میشود و برای میزبانی برنامه شما قابل دسترسی است.
مولفه خلاصه بررسی را پیاده سازی کنید
- در
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>; } }
- یک commit با پیام commit "استفاده از هوش مصنوعی برای خلاصه کردن نظرات" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبانی برنامه را در کنسول Firebase باز کنید و منتظر بمانید تا عرضه جدید شما تکمیل شود.
- یک صفحه برای رستوران باز کنید. در بالا، باید خلاصهای از تمام نظرات موجود در صفحه را یک جمله ببینید.
- یک بررسی جدید اضافه کنید و صفحه را بازخوانی کنید. شما باید تغییر خلاصه را ببینید.
11. نتیجه گیری
تبریک می گویم! یاد گرفتید که چگونه از Firebase برای افزودن ویژگیها و عملکرد به برنامه Next.js استفاده کنید. به طور خاص از موارد زیر استفاده کردید:
- میزبانی برنامه Firebase برای ساخت و استقرار خودکار کد Next.js شما با هر بار فشار دادن به یک شاخه پیکربندی شده.
- احراز هویت Firebase برای فعال کردن عملکرد ورود و خروج از سیستم.
- Cloud Firestore برای دادههای رستوران و دادههای بررسی رستوران.
- Cloud Storage برای Firebase برای تصاویر رستوران.
بیشتر بدانید
1. قبل از شروع
در این کد لبه، یاد خواهید گرفت که چگونه Firebase را با یک برنامه وب Next.js به نام Friendly Eats که یک وب سایت برای بررسی رستوران ها است، ادغام کنید.
برنامه وب تکمیل شده ویژگی های مفیدی را ارائه می دهد که نشان می دهد Firebase چگونه می تواند به شما در ساخت برنامه های Next.js کمک کند. این ویژگی ها شامل موارد زیر است:
- ساخت و استقرار خودکار: این کد لبه از میزبانی برنامه Firebase برای ساخت و استقرار خودکار کد Next.js شما هر بار که به یک شاخه پیکربندی شده فشار میدهید، استفاده میکند.
- ورود و خروج: برنامه وب تکمیل شده به شما امکان می دهد با Google وارد شوید و از سیستم خارج شوید. ورود و تداوم کاربر به طور کامل از طریق Firebase Authentication مدیریت می شود.
- تصاویر: برنامه وب تکمیل شده به کاربرانی که وارد سیستم شده اند اجازه می دهد تصاویر رستوران را آپلود کنند. دارایی های تصویر در Cloud Storage برای Firebase ذخیره می شوند. Firebase JavaScript SDK یک URL عمومی برای تصاویر آپلود شده فراهم می کند. سپس این URL عمومی در سند رستوران مربوطه در Cloud Firestore ذخیره میشود.
- نظرات: برنامه وب تکمیلشده به کاربرانی که وارد سیستم شدهاند اجازه میدهد نظرات رستورانهایی را که شامل رتبهبندی ستاره و پیام متنی هستند، ارسال کنند. اطلاعات مرور در Cloud Firestore ذخیره می شود.
- فیلترها: برنامه وب تکمیلشده به کاربرانی که وارد سیستم شدهاند اجازه میدهد فهرست رستورانها را بر اساس دسته، مکان و قیمت فیلتر کنند. همچنین می توانید روش مرتب سازی مورد استفاده را سفارشی کنید. داده ها از Cloud Firestore قابل دسترسی هستند و پرس و جوهای Firestore بر اساس فیلترهای استفاده شده اعمال می شوند.
پیش نیازها
- یک حساب GitHub
- آشنایی با Next.js و جاوا اسکریپت
چیزی که یاد خواهید گرفت
- نحوه استفاده از Firebase با روتر برنامه Next.js و رندر سمت سرور.
- نحوه ماندگاری تصاویر در Cloud Storage برای Firebase.
- نحوه خواندن و نوشتن داده ها در پایگاه داده Cloud Firestore.
- نحوه استفاده از ورود به سیستم با Google با Firebase JavaScript SDK.
آنچه شما نیاز دارید
- Git
- نسخه پایدار اخیر Node.js
- مرورگر دلخواه شما، مانند گوگل کروم
- یک محیط توسعه با ویرایشگر کد و ترمینال
- یک حساب Google برای ایجاد و مدیریت پروژه Firebase شما
- توانایی ارتقاء پروژه Firebase خود به طرح قیمت گذاری Blaze
2. محیط توسعه و مخزن GitHub خود را راه اندازی کنید
این لبه کد پایه کد شروع برنامه را فراهم می کند و به Firebase CLI متکی است.
یک مخزن GitHub ایجاد کنید
منبع Codelab را می توان در https://github.com/firebase/friendlyeats-web یافت. این مخزن شامل پروژه های نمونه برای پلتفرم های متعدد است. با این حال، این کد لبه فقط از دایرکتوری 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
- از بسته giget npm برای واکشی فقط پوشه
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>
کنید.git remote add origin <REPOSITORY_URL> git push -u origin main
- اکنون باید کد شروع را در مخزن GitHub خود مشاهده کنید.
Firebase CLI را نصب یا بهروزرسانی کنید
برای تأیید اینکه Firebase CLI را نصب کرده اید و نسخه 14.1.0 یا بالاتر است، دستور زیر را اجرا کنید:
firebase --version
اگر نسخه پایینتری میبینید یا Firebase CLI را نصب نکردهاید، دستور install را اجرا کنید:
npm install -g firebase-tools@latest
اگر به دلیل خطاهای مجوز نمی توانید Firebase CLI را نصب کنید، اسناد npm را ببینید یا از گزینه نصب دیگری استفاده کنید.
وارد Firebase شوید
- برای ورود به Firebase CLI دستور زیر را اجرا کنید:
firebase login
- بسته به اینکه می خواهید Firebase داده ها را جمع آوری کند،
Y
یاN
را وارد کنید. - در مرورگر خود، حساب Google خود را انتخاب کنید و سپس روی Allow کلیک کنید.
3. پروژه Firebase خود را راه اندازی کنید
در این بخش، یک پروژه Firebase را راهاندازی کرده و یک برنامه وب Firebase را با آن مرتبط میکنید. همچنین سرویسهای Firebase را که توسط برنامه وب نمونه استفاده میشود، راهاندازی میکنید.
یک پروژه Firebase ایجاد کنید
- در کنسول Firebase ، روی افزودن پروژه کلیک کنید.
- در کادر متنی نام پروژه خود را وارد کنید ،
FriendlyEats Codelab
(یا نام پروژه دلخواهتان) را وارد کنید و سپس روی Continue کلیک کنید. - برای این کد لبه، شما نیازی به Google Analytics ندارید، بنابراین گزینه Enable Google Analytics for this project را غیرفعال کنید.
- روی ایجاد پروژه کلیک کنید.
- منتظر بمانید تا پروژه شما ارائه شود و سپس روی Continue کلیک کنید.
- در پروژه Firebase خود، به تنظیمات پروژه بروید. شناسه پروژه خود را یادداشت کنید زیرا بعداً به آن نیاز دارید. این شناسه منحصر به فرد نحوه شناسایی پروژه شما است (به عنوان مثال، در Firebase CLI).
طرح قیمت گذاری Firebase خود را ارتقا دهید
برای استفاده از میزبانی برنامه Firebase و فضای ذخیرهسازی ابری برای Firebase، پروژه Firebase شما باید در طرح قیمتگذاری (Blaze) باشد، به این معنی که به یک حساب صورتحساب Cloud مرتبط است.
- حساب Cloud Billing به یک روش پرداخت مانند کارت اعتباری نیاز دارد.
- اگر تازه وارد Firebase و Google Cloud هستید، بررسی کنید که آیا واجد شرایط دریافت اعتبار 300 دلاری و یک حساب آزمایشی رایگان Cloud Billing هستید یا خیر.
- اگر این نرمافزار کد را بهعنوان بخشی از یک رویداد انجام میدهید، از سازماندهنده خود بپرسید که آیا اعتبارات Cloud موجود است یا خیر.
برای ارتقای پروژه خود به پلن Blaze، مراحل زیر را دنبال کنید:
- در کنسول Firebase، برنامه خود را ارتقا دهید .
- طرح Blaze را انتخاب کنید. دستورالعمل های روی صفحه را دنبال کنید تا یک حساب Cloud Billing را به پروژه خود پیوند دهید.
اگر به عنوان بخشی از این ارتقاء نیاز به ایجاد یک حساب Cloud Billing داشتید، ممکن است لازم باشد برای تکمیل ارتقاء به جریان ارتقاء در کنسول Firebase برگردید.
یک برنامه وب را به پروژه Firebase خود اضافه کنید
- به بررسی اجمالی پروژه خود در پروژه Firebase خود بروید و سپس کلیک کنید
وب
اگر قبلاً برنامه هایی را در پروژه خود ثبت کرده اید ، برای دیدن نماد وب روی Add App برنامه کلیک کنید. - در کادر متن نام مستعار برنامه ، یک نام مستعار برنامه به یاد ماندنی مانند
My Next.js app
وارد کنید. - همچنین میزبان تنظیمات Firebase را برای این کادر انتخاب برنامه بدون بررسی نگه دارید.
- روی Register App> Console را ادامه دهید .
خدمات Firebase را در کنسول Firebase تنظیم کنید
احراز هویت را تنظیم کنید
- در کنسول Firebase ، به تأیید اعتبار بروید.
- روی Get start کلیک کنید.
- در ستون ارائه دهندگان اضافی ، روی Google> Enable کلیک کنید.
- در نام عمومی برای جعبه متن پروژه ، یک نام به یاد ماندنی مانند
My Next.js app
وارد کنید. - از ایمیل پشتیبانی برای کشویی پروژه ، آدرس ایمیل خود را انتخاب کنید.
- روی ذخیره کلیک کنید.
Firestore Cloud را تنظیم کنید
- در صفحه چپ کنسول Firebase ، ساخت را گسترش داده و سپس پایگاه داده Firestore را انتخاب کنید.
- روی ایجاد پایگاه داده کلیک کنید.
- شناسه پایگاه داده را روی
(default)
تنظیم کنید. - مکانی را برای پایگاه داده خود انتخاب کنید ، سپس روی Next کلیک کنید.
برای یک برنامه واقعی ، می خواهید مکانی را انتخاب کنید که نزدیک کاربران شما باشد. - روی حالت شروع در حالت تست کلیک کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید.
بعداً در این CodeLab ، قوانین امنیتی را برای تأمین اطلاعات خود اضافه می کنید. بدون اضافه کردن قوانین امنیتی برای پایگاه داده خود ، یک برنامه را به صورت عمومی توزیع یا افشا نکنید . - روی ایجاد کلیک کنید.
فضای ذخیره سازی ابری را برای Firebase تنظیم کنید
- در صفحه چپ کنسول Firebase ، ساخت را گسترش داده و سپس ذخیره سازی را انتخاب کنید.
- روی Get start کلیک کنید.
- مکانی را برای سطل ذخیره سازی پیش فرض خود انتخاب کنید.
سطل درUS-WEST1
،US-CENTRAL1
وUS-EAST1
می توانند از ردیف "همیشه رایگان" برای Google Cloud Storage استفاده کنند. سطل های موجود در همه مکان های دیگر از قیمت گذاری و استفاده از Google Cloud Cloud پیروی می کنند. - روی حالت شروع در حالت تست کلیک کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید.
بعداً در این CodeLab ، قوانین امنیتی را برای تأمین اطلاعات خود اضافه می کنید. بدون اضافه کردن قوانین امنیتی برای سطل ذخیره سازی خود ، یک برنامه را به صورت عمومی توزیع یا افشا نکنید . - روی ایجاد کلیک کنید.
اعزام قوانین امنیتی
این کد در حال حاضر مجموعه ای از قوانین امنیتی را برای Firestore و برای ذخیره سازی ابری برای 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
را فشار دهید تا بله را انتخاب کنید.
4. پایگاه کد استارت را مرور کنید
در این بخش ، چند زمینه از پایگاه کد استارت برنامه را که به آن عملکردی را در این CodeLab اضافه می کنید ، مرور خواهید کرد.
پوشه و ساختار پرونده
جدول زیر حاوی مروری بر پوشه و ساختار پرونده برنامه است:
پوشه ها و فایل ها | توضیحات |
| مؤلفه های 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
تمام کد API Firebase در فهرست src/lib/firebase
پیچیده شده است. مؤلفه های React انفرادی سپس توابع بسته بندی شده را از فهرست src/lib/firebase
وارد می کنند ، نه اینکه توابع Firebase را مستقیماً وارد کنید.
داده های ساختگی
رستوران مسخره و داده های مرور در پرونده src/lib/randomData.js
موجود است. داده های این پرونده در کد در پرونده src/lib/fakeRestaurants.js
جمع آوری شده است.
5. یک برنامه پشتیبان میزبان برنامه ایجاد کنید
در این بخش ، یک برنامه میزبان میزبان برای تماشای شعبه ای در مخزن Git خود تنظیم می کنید.
در پایان این بخش ، یک برنامه میزبان برنامه ای که به مخزن خود در GitHub متصل است ، خواهید داشت که به طور خودکار دوباره ساخت و نسخه جدیدی از برنامه خود را در هر زمان که به یک تعهد جدید به شعبه main
خود بپردازید ، دوباره بسازید و نسخه جدیدی از برنامه خود را بسازید.
یک Backend ایجاد کنید
- به صفحه میزبانی برنامه در کنسول Firebase بروید:
- برای شروع جریان ایجاد Backend ، روی "شروع کار" کلیک کنید. پس زمینه خود را به شرح زیر پیکربندی کنید:
- یک منطقه را انتخاب کنید. برای یک برنامه واقعی ، منطقه را نزدیک به کاربران خود انتخاب می کنید.
- برای اتصال مخزن GitHub که قبلاً ایجاد کرده اید ، در مرحله "واردات یک مخزن GitHub" دنبال کنید.
- تنظیمات استقرار را تنظیم کنید:
- دایرکتوری ریشه را به عنوان
/
نگه دارید - شعبه زنده را روی
main
تنظیم کنید - برنامه های اتوماتیک را فعال کنید
- دایرکتوری ریشه را به عنوان
- نامزد خود را
friendlyeats-codelab
نامگذاری کنید. - در "Associate A Firebase Web Web" ، روی "ایجاد یک برنامه وب Firebase جدید" کلیک کنید.
- روی "پایان و استقرار" کلیک کنید. بعد از یک لحظه ، به صفحه جدیدی منتقل می شوید که می توانید وضعیت برنامه جدید میزبانی برنامه خود را با پشتیبانی کنید!
- پس از اتمام کار خود ، روی دامنه رایگان خود در زیر "دامنه ها" کلیک کنید. این ممکن است به دلیل انتشار DNS چند دقیقه طول بکشد.
- اوه اوه هنگامی که صفحه را بارگیری می کنید ، یک پیام خطایی را مشاهده خواهید کرد که می گوید "خطای برنامه: یک استثناء سمت سرور رخ داده است (برای اطلاعات بیشتر به گزارش های سرور مراجعه کنید).
- در کنسول Firebase ، برگه "سیاهههای مربوط" میزبان میزبان خود را بررسی کنید. ورود به سیستم "خطا: اجرا نشده" را مشاهده خواهید کرد. ما در مرحله بعدی وقتی که تأیید اعتبار را اضافه می کنیم ، آن را برطرف خواهیم کرد.
شما برنامه وب اولیه را مستقر کرده اید! هربار که تعهد جدیدی را به شاخه main
مخزن GitHub خود سوق دهید ، شاهد ساخت و ساخت جدید در کنسول Firebase خواهید بود و پس از اتمام کار ، سایت شما به طور خودکار به روز می شود.
6. احراز هویت را به برنامه وب اضافه کنید
در این بخش ، تأیید اعتبار را به برنامه وب اضافه می کنید تا بتوانید وارد آن شوید.
یک دامنه مجاز اضافه کنید
احراز هویت Firebase فقط ورود به درخواست های دامنه هایی را که اجازه می دهید ، می پذیرد. در اینجا ، ما برنامه شما میزبان دامنه Backend را به لیست دامنه های تأیید شده در پروژه شما اضافه خواهیم کرد.
- برنامه تور میزبان دامنه Backend را از صفحه "نمای کلی" میزبان برنامه کپی کنید.
- به برگه تنظیمات AUTH بروید و دامنه های مجاز را انتخاب کنید.
- روی دکمه افزودن دامنه کلیک کنید.
- برنامه خود را میزبان دامنه Backend وارد کنید.
عملکردهای ورود به سیستم و ورود به سیستم را پیاده سازی کنید
- در پرونده
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 زیر استفاده می کند:
API Firebase | توضیحات |
یک ناظر را برای تغییر در وضعیت ورود به کاربر اضافه می کند. | |
یک ناظر را برای تغییر در نشانه شناسه کاربر اضافه می کند. | |
یک نمونه ارائه دهنده احراز هویت Google ایجاد می کند. | |
جریان احراز هویت مبتنی بر گفتگو را شروع می کند. | |
کاربر را امضا می کند. |
در پرونده src/components/Header.jsx
، کد قبلاً توابع signInWithGoogle
و signOut
فراخوانی می کند.
وضعیت احراز هویت را به سرور ارسال کنید
برای انتقال وضعیت احراز هویت به سرور ، از کوکی ها استفاده خواهیم کرد. هر زمان که وضعیت تأیید اعتبار در مشتری تغییر کند ، ما کوکی __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>
در صورت وجود سرور ، داده های کاربر را در صورت وجود ارائه می دهد. اگر به روزرسانی احراز هویت در طول چرخه عمر صفحه پس از بار اولیه صفحه وجود داشته باشد ، کنترل کننده onAuthStateChanged
آنها را کنترل می کند.
اکنون وقت آن رسیده است که یک ساخت جدید را بیرون بیاورید و آنچه را که ساخته اید تأیید کنید.
- با پیام متعهد "اضافه کردن احراز هویت" تعهد ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبان برنامه را در کنسول Firebase باز کنید و منتظر تکمیل برنامه جدید خود باشید.
- رفتار احراز هویت جدید را تأیید کنید:
- در مرورگر خود ، برنامه وب را تازه کنید. نام نمایش شما در هدر ظاهر می شود.
- ثبت نام کنید و دوباره وارد شوید. می توانید این مرحله را با کاربران مختلف تکرار کنید.
- اختیاری: بر روی برنامه وب راست کلیک کنید ، صفحه نمایش را انتخاب کنید و نام نمایش را جستجو کنید. در منبع HTML خام برگشتی از سرور ظاهر می شود.
7. مشاهده اطلاعات رستوران
برنامه وب شامل داده های مسخره برای رستوران ها و بررسی ها است.
یک یا چند رستوران اضافه کنید
برای وارد کردن داده های رستوران مسخره در پایگاه داده محلی Firestore Cloud ، این مراحل را دنبال کنید:
- اگر قبلاً این کار را نکرده اید وارد برنامه وب شوید. سپس، انتخاب کنید
> اضافه کردن رستوران های نمونه .
- در کنسول Firebase در صفحه پایگاه داده Firestore ، رستوران ها را انتخاب کنید. شما اسناد سطح بالا را در مجموعه رستوران ها مشاهده می کنید که هر یک از آنها یک رستوران را نشان می دهد.
- برای کشف خواص یک سند رستوران ، چند سند را کلیک کنید.
لیست رستوران ها را نمایش دهید
پایگاه داده 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 باز کنید و منتظر تکمیل برنامه جدید خود باشید.
- در برنامه وب ، صفحه را تازه کنید. تصاویر رستوران به عنوان کاشی در صفحه ظاهر می شوند.
تأیید کنید که لیست رستوران ها در زمان اجرای سرور بارگیری می شود
با استفاده از چارچوب Next.js ، ممکن است هنگام بارگیری داده ها در زمان اجرای سرور یا زمان اجرای مشتری بارگذاری شود.
برای تأیید اینکه لیست رستوران ها در زمان اجرای سرور بارگذاری می شود ، این مراحل را دنبال کنید:
- در برنامه وب ، DevTools را باز کنید و JavaScript را غیرفعال کنید .
- برنامه وب را تازه کنید. لیست رستوران ها هنوز هم بارگیری می شوند. اطلاعات رستوران در پاسخ سرور بازگردانده می شود. هنگامی که JavaScript فعال شد ، اطلاعات رستوران از طریق کد JavaScript طرف مشتری هیدراته می شود.
- در DevTools ، JavaScript را دوباره فعال کنید .
به روزرسانی های رستوران با شنوندگان عکس فرکه 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 اکنون در برنامه وب در زمان واقعی منعکس می شود.
- با پیام تعهد "گوش دادن به به روزرسانی های رستوران Realtime" ایجاد کنید و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبان برنامه را در کنسول 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;
}
}
اجرای یک سرور بعدی. js
یک عمل سرور Next.JS یک API مناسب برای دسترسی به داده های فرم مانند data.get("text")
فراهم می کند تا مقدار متن را از بار ارسال فرم دریافت کند.
برای استفاده از یک عمل سرور 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"),
});
}
برای یک رستوران نظرات اضافه کنید
شما پشتیبانی را برای ارسال های مرور انجام داده اید ، بنابراین اکنون می توانید تأیید کنید که بررسی های شما به درستی در Firestore Cloud وارد شده است.
برای افزودن یک بررسی و تأیید اینکه در Firestore Cloud وارد شده است ، این مراحل را دنبال کنید:
- با پیام متعهد "به کاربران اجازه دهید بررسی رستوران ها را ارسال کنند" و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبان برنامه را در کنسول Firebase باز کنید و منتظر تکمیل برنامه جدید خود باشید.
- برنامه وب را تازه کنید و یک رستوران را از صفحه اصلی انتخاب کنید.
- در صفحه رستوران ، کلیک کنید
.
- رتبه بندی ستاره را انتخاب کنید.
- یک بررسی بنویسید.
- روی ارسال کلیک کنید. بررسی شما در صدر لیست بررسی ها ظاهر می شود.
- در Cloud Firestore ، صفحه Add Document را برای سند رستوران که بررسی کرده اید جستجو کنید و آن را انتخاب کنید.
- در صفحه شروع مجموعه ، رتبه بندی ها را انتخاب کنید.
- در صفحه Add Document ، سند را برای بررسی خود پیدا کنید تا تأیید کنید که همانطور که انتظار می رود درج شده است.
9. فایلهای بارگیری شده توسط کاربر را از برنامه وب ذخیره کنید
در این بخش ، عملکردی را اضافه می کنید تا بتوانید هنگام ورود به سیستم ، تصویر مرتبط با یک رستوران را جایگزین کنید. تصویر را در ذخیره سازی Firebase بارگذاری می کنید و URL تصویر را در سند Firestore Cloud که نمایانگر رستوران است ، به روز می کنید.
برای ذخیره پرونده های بارگیری کاربر از برنامه وب ، این مراحل را دنبال کنید:
- در پرونده
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()
قبلاً برای شما پیاده سازی شده است. این عملکرد یک سند رستوران موجود را در Firestore Cloud با URL به روز شده تصویر به روز می کند.
عملکرد تصویر و بارگیری را تأیید کنید
برای تأیید اینکه تصویر همانطور که انتظار می رود بارگذاری می شود ، این مراحل را دنبال کنید:
- با پیام متعهد "به کاربران اجازه دهید عکس هر رستوران را تغییر دهند" و آن را به مخزن GitHub خود فشار دهید.
- صفحه میزبان برنامه را در کنسول Firebase باز کنید و منتظر تکمیل برنامه جدید خود باشید.
- در برنامه وب ، تأیید کنید که وارد سیستم شده اید و یک رستوران را انتخاب کنید.
- کلیک کنید
و یک تصویر را از سیستم پرونده خود بارگذاری کنید. تصویر شما محیط محلی شما را ترک می کند و در ذخیره سازی ابری بارگذاری می شود. تصویر بلافاصله پس از بارگذاری آن ظاهر می شود.
- برای Firebase به ذخیره سازی ابری بروید.
- به پوشه ای که نماینده رستوران است بروید. تصویری که بارگذاری کرده اید در پوشه وجود دارد.
10. بررسی های رستوران ها را با هوش مصنوعی خلاصه کنید
در این بخش ، یک ویژگی خلاصه بررسی را اضافه می کنید تا کاربر بتواند بدون نیاز به خواندن هر بررسی ، همه آنچه را که درباره یک رستوران فکر می کند درک کند.
یک کلید API Gemini را در Cloud Secret Manager ذخیره کنید
- برای استفاده از API Gemini ، به یک کلید API نیاز دارید. به استودیوی Google AI مراجعه کرده و روی "ایجاد کلید API" کلیک کنید.
- در ورودی "Search Google Cloud Projects" ، پروژه Firebase خود را انتخاب کنید. هر پروژه Firebase توسط یک پروژه Google Cloud پشتیبانی می شود.
- میزبانی برنامه با Cloud Secret Manager ادغام می شود تا به شما امکان می دهد مقادیر حساس مانند کلیدهای API را به طور ایمن ذخیره کنید:
- در یک ترمینال ، دستور ایجاد یک راز جدید را اجرا کنید:
firebase apphosting:secrets:set GEMINI_API_KEY
- هنگامی که از ارزش مخفی خواسته شد ، کلید API Gemini خود را از استودیوی Google AI کپی و چسبانده اید.
- وقتی از وی سؤال شد که آیا راز جدید برای تولید یا آزمایش محلی است ، "تولید" را انتخاب کنید.
- وقتی از شما سؤال می شود که آیا می خواهید دسترسی پیدا کنید تا حساب خدمات پس زمینه شما بتواند به راز دسترسی پیدا کند ، "بله" را انتخاب کنید.
- در پاسخ به این سؤال که آیا راز جدید باید به
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 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 برای خلاصه بررسی ها استفاده کنید" ایجاد کنید و آن را به مخزن GitHub خود سوق دهید.
- صفحه میزبان برنامه را در کنسول Firebase باز کنید و منتظر تکمیل برنامه جدید خود باشید.
- یک صفحه برای یک رستوران باز کنید. در بالا ، شما باید خلاصه یک جمله از تمام بررسی های موجود در صفحه را ببینید.
- یک بررسی جدید اضافه کنید و صفحه را تازه کنید. شما باید تغییر خلاصه را ببینید.
11. نتیجه گیری
تبریک می گویم! شما یاد گرفتید که چگونه از Firebase برای اضافه کردن ویژگی ها و عملکرد به یک برنامه Next.js استفاده کنید. به طور خاص ، شما از موارد زیر استفاده کرده اید:
- میزبان برنامه Firebase برای ساخت و مستقر کردن کد NEXT.JS هر بار که به یک شاخه پیکربندی شده فشار می آورید.
- احراز هویت Firebase برای فعال کردن قابلیت ورود به سیستم و ورود به سیستم.
- Firestore Cloud برای داده های رستوران و داده های بررسی رستوران.
- ذخیره سازی ابری برای Firebase برای تصاویر رستوران.
بیشتر بدانید
1. قبل از شروع
در این CodeLab ، شما می آموزید که چگونه Firebase را با یک برنامه وب Next.js به نام Friendly Eats ادغام کنید ، که یک وب سایت برای بررسی رستوران ها است.
برنامه وب تکمیل شده ویژگی های مفیدی را ارائه می دهد که نشان می دهد چگونه Firebase می تواند به شما در ساخت برنامه های Next.js کمک کند. این ویژگی ها شامل موارد زیر است:
- ساخت و استقرار خودکار: این CodeLab از میزبان برنامه Firebase برای ساخت و مستقر کردن کد بعدی خود استفاده می کند. هر بار که به یک شاخه پیکربندی شده فشار می آورید.
- ورود به سیستم و ورود به سیستم: برنامه وب تکمیل شده به شما امکان می دهد با Google وارد شوید و از سیستم خارج شوید. ورود و پایداری کاربر به طور کامل از طریق احراز هویت Firebase اداره می شود.
- تصاویر: برنامه وب تکمیل شده اجازه می دهد تا کاربران امضا شده تصاویر رستوران را بارگذاری کنند. دارایی های تصویر در فضای ذخیره سازی برای Firebase ذخیره می شوند. Firebase JavaScript SDK یک URL عمومی برای تصاویر بارگذاری شده ارائه می دهد. این URL عمومی سپس در سند رستوران مربوطه در Firestore Cloud ذخیره می شود.
- بررسی ها: برنامه وب تکمیل شده به کاربران امضا شده اجازه می دهد تا در مورد رستوران هایی که از یک رتبه بندی ستاره و یک پیام مبتنی بر متن تشکیل شده اند ، بررسی کنند. اطلاعات مرور در Firestore Cloud ذخیره می شود.
- فیلترها: برنامه وب تکمیل شده به کاربران وارد شده اجازه می دهد تا لیست رستوران ها را بر اساس طبقه بندی ، مکان و قیمت فیلتر کنند. همچنین می توانید روش مرتب سازی مورد استفاده را سفارشی کنید. داده ها از Firestore Cloud قابل دسترسی است و نمایش داده های Firestore بر اساس فیلترهای مورد استفاده اعمال می شود.
پیش نیازها
- یک حساب GitHub
- دانش Next.js و JavaScript
چیزی که یاد خواهید گرفت
- نحوه استفاده از Firebase با روتر برنامه Next.js و ارائه سمت سرور.
- چگونه می توان تصاویر را در فضای ذخیره سازی ابری برای Firebase ادامه داد.
- نحوه خواندن و نوشتن داده ها در یک پایگاه داده Firestore Cloud.
- نحوه استفاده از ورود به سیستم با Google با Firebase JavaScript SDK.
آنچه شما نیاز دارید
- Git
- نسخه پایدار اخیر Node.js
- مرورگر مورد نظر شما ، مانند Google Chrome
- یک محیط توسعه با ویرایشگر کد و ترمینال
- حساب Google برای ایجاد و مدیریت پروژه Firebase شما
- امکان به روزرسانی پروژه Firebase خود به برنامه قیمت گذاری Blaze
2. محیط توسعه و مخزن GitHub خود را تنظیم کنید
این CodeLab Code Code Starter برنامه را ارائه می دهد و به CLI Firebase متکی است.
یک مخزن 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
- برای واکشی فقط پوشه
nextjs-start
از بسته Giget NPM استفاده کنید: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 خود فشار دهید. URL مخزن واقعی خود را برای نگهدارنده مکان
<REPOSITORY_URL>
جایگزین کنید.git remote add origin <REPOSITORY_URL> git push -u origin main
- اکنون باید کد استارت را در مخزن GitHub خود مشاهده کنید.
Firebase CLI را نصب یا به روز کنید
دستور زیر را اجرا کنید تا تأیید کنید که Firebase CLI را نصب کرده اید و V14.1.0 یا بالاتر است:
firebase --version
اگر نسخه پایین تری را مشاهده می کنید یا Firebase CLI را نصب نکرده اید ، دستور نصب را اجرا کنید:
npm install -g firebase-tools@latest
اگر به دلیل خطاهای اجازه قادر به نصب Firebase CLI نیستید ، به اسناد NPM مراجعه کنید یا از گزینه نصب دیگری استفاده کنید.
وارد Firebase شوید
- دستور زیر را برای ورود به Firebase CLI اجرا کنید:
firebase login
- بسته به اینکه آیا می خواهید Firebase برای جمع آوری داده ها ،
Y
یاN
را وارد کنید. - در مرورگر خود ، حساب Google خود را انتخاب کرده و سپس روی Allows کلیک کنید.
3. پروژه Firebase خود را تنظیم کنید
در این بخش ، یک پروژه Firebase را تنظیم کرده و یک برنامه وب Firebase را با آن مرتبط می کنید. شما همچنین می توانید خدمات Firebase را که توسط برنامه وب نمونه استفاده شده است ، تنظیم کنید.
یک پروژه Firebase ایجاد کنید
- در کنسول Firebase ، روی Add Project کلیک کنید.
- در کادر متن نام پروژه خود را وارد کنید ،
FriendlyEats Codelab
(یا نام پروژه مورد نظر خود) را وارد کنید و سپس روی ادامه کلیک کنید. - برای این CodeLab ، شما به Google Analytics احتیاج ندارید ، بنابراین Google Analytics را برای این گزینه پروژه فعال کنید.
- روی ایجاد پروژه کلیک کنید.
- صبر کنید تا پروژه خود را تأمین کند ، و سپس بر روی ادامه کلیک کنید.
- در پروژه Firebase خود به تنظیمات پروژه بروید. به شناسه پروژه خود توجه داشته باشید زیرا بعداً به آن احتیاج دارید. این شناسه منحصر به فرد نحوه شناسایی پروژه شما (به عنوان مثال ، در Firebase CLI) است.
برنامه قیمت گذاری Firebase خود را ارتقا دهید
برای استفاده از میزبانی برنامه Firebase و ذخیره سازی ابری برای Firebase ، پروژه Firebase شما باید در برنامه قیمت گذاری Pay-As-As-You Go (Blaze) باشد ، این بدان معنی است که با یک حساب صورتحساب ابری مرتبط است.
- یک حساب صورتحساب ابر مانند کارت اعتباری به یک روش پرداخت نیاز دارد.
- اگر تازه وارد Firebase و Google Cloud هستید ، بررسی کنید که آیا واجد شرایط اعتبار 300 دلاری و یک حساب صورتحساب ابری آزمایشی رایگان هستید.
- اگر این CodeLab را به عنوان بخشی از یک رویداد انجام می دهید ، از سازمان دهنده خود بپرسید که آیا اعتبار ابری در دسترس است یا خیر.
برای به روزرسانی پروژه خود به برنامه Blaze ، این مراحل را دنبال کنید:
- در کنسول Firebase ، برای به روزرسانی برنامه خود انتخاب کنید.
- طرح Blaze را انتخاب کنید. دستورالعمل های روی صفحه را دنبال کنید تا یک حساب صورتحساب ابر به پروژه خود پیوند دهید.
اگر به عنوان بخشی از این به روزرسانی نیاز به ایجاد یک حساب صورتحساب ابری دارید ، ممکن است لازم باشد که برای تکمیل به روزرسانی به جریان ارتقاء موجود در کنسول Firebase بروید.
یک برنامه وب را به پروژه Firebase خود اضافه کنید
- به بررسی اجمالی پروژه خود در پروژه Firebase خود بروید و سپس کلیک کنید
وب
اگر قبلاً برنامه هایی را در پروژه خود ثبت کرده اید ، برای دیدن نماد وب روی Add App برنامه کلیک کنید. - در کادر متن نام مستعار برنامه ، یک نام مستعار برنامه به یاد ماندنی مانند
My Next.js app
وارد کنید. - همچنین میزبان تنظیمات Firebase را برای این کادر انتخاب برنامه بدون بررسی نگه دارید.
- روی Register App> Console را ادامه دهید .
خدمات Firebase را در کنسول Firebase تنظیم کنید
احراز هویت را تنظیم کنید
- در کنسول Firebase ، به تأیید اعتبار بروید.
- روی Get start کلیک کنید.
- در ستون ارائه دهندگان اضافی ، روی Google> Enable کلیک کنید.
- در نام عمومی برای جعبه متن پروژه ، یک نام به یاد ماندنی مانند
My Next.js app
وارد کنید. - از ایمیل پشتیبانی برای کشویی پروژه ، آدرس ایمیل خود را انتخاب کنید.
- روی ذخیره کلیک کنید.
Firestore Cloud را تنظیم کنید
- در صفحه چپ کنسول Firebase ، ساخت را گسترش داده و سپس پایگاه داده Firestore را انتخاب کنید.
- روی ایجاد پایگاه داده کلیک کنید.
- شناسه پایگاه داده را روی
(default)
تنظیم کنید. - مکانی را برای پایگاه داده خود انتخاب کنید ، سپس روی Next کلیک کنید.
برای یک برنامه واقعی ، می خواهید مکانی را انتخاب کنید که نزدیک کاربران شما باشد. - روی حالت شروع در حالت تست کلیک کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید.
بعداً در این CodeLab ، قوانین امنیتی را برای تأمین اطلاعات خود اضافه می کنید. بدون اضافه کردن قوانین امنیتی برای پایگاه داده خود ، یک برنامه را به صورت عمومی توزیع یا افشا نکنید . - روی ایجاد کلیک کنید.
فضای ذخیره سازی ابری را برای Firebase تنظیم کنید
- در صفحه چپ کنسول Firebase ، ساخت را گسترش داده و سپس ذخیره سازی را انتخاب کنید.
- روی Get start کلیک کنید.
- مکانی را برای سطل ذخیره سازی پیش فرض خود انتخاب کنید.
سطل درUS-WEST1
،US-CENTRAL1
وUS-EAST1
می توانند از ردیف "همیشه رایگان" برای Google Cloud Storage استفاده کنند. سطل های موجود در همه مکان های دیگر از قیمت گذاری و استفاده از Google Cloud Cloud پیروی می کنند. - روی حالت شروع در حالت تست کلیک کنید. سلب مسئولیت در مورد قوانین امنیتی را بخوانید.
بعداً در این CodeLab ، قوانین امنیتی را برای تأمین اطلاعات خود اضافه می کنید. بدون اضافه کردن قوانین امنیتی برای سطل ذخیره سازی خود ، یک برنامه را به صورت عمومی توزیع یا افشا نکنید . - روی ایجاد کلیک کنید.
اعزام قوانین امنیتی
این کد در حال حاضر مجموعه ای از قوانین امنیتی را برای Firestore و برای ذخیره سازی ابری برای 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
را فشار دهید تا بله را انتخاب کنید.
4. پایگاه کد استارت را مرور کنید
در این بخش ، چند زمینه از پایگاه کد استارت برنامه را که به آن عملکردی را در این CodeLab اضافه می کنید ، مرور خواهید کرد.
پوشه و ساختار پرونده
جدول زیر حاوی مروری بر پوشه و ساختار پرونده برنامه است:
پوشه ها و فایل ها | توضیحات |
| مؤلفه های 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
تمام کد API Firebase در فهرست src/lib/firebase
پیچیده شده است. مؤلفه های React انفرادی سپس توابع بسته بندی شده را از فهرست src/lib/firebase
وارد می کنند ، نه اینکه توابع Firebase را مستقیماً وارد کنید.
داده های ساختگی
رستوران مسخره و داده های مرور در پرونده src/lib/randomData.js
موجود است. داده های این پرونده در کد در پرونده src/lib/fakeRestaurants.js
جمع آوری شده است.
5. یک برنامه پشتیبان میزبان برنامه ایجاد کنید
در این بخش ، یک برنامه میزبان میزبان برای تماشای شعبه ای در مخزن Git خود تنظیم می کنید.
در پایان این بخش ، یک برنامه میزبان برنامه ای که به مخزن خود در GitHub متصل است ، خواهید داشت که به طور خودکار دوباره ساخت و نسخه جدیدی از برنامه خود را در هر زمان که به یک تعهد جدید به شعبه main
خود بپردازید ، دوباره بسازید و نسخه جدیدی از برنامه خود را بسازید.
یک Backend ایجاد کنید
- به صفحه میزبانی برنامه در کنسول Firebase بروید:
- برای شروع جریان ایجاد Backend ، روی "شروع کار" کلیک کنید. پس زمینه خود را به شرح زیر پیکربندی کنید:
- یک منطقه را انتخاب کنید. برای یک برنامه واقعی ، منطقه را نزدیک به کاربران خود انتخاب می کنید.
- برای اتصال مخزن GitHub که قبلاً ایجاد کرده اید ، در مرحله "واردات یک مخزن GitHub" دنبال کنید.
- تنظیمات استقرار را تنظیم کنید:
- دایرکتوری ریشه را به عنوان
/
نگه دارید - شعبه زنده را روی
main
تنظیم کنید - برنامه های اتوماتیک را فعال کنید
- دایرکتوری ریشه را به عنوان
- نامزد خود را
friendlyeats-codelab
نامگذاری کنید. - در "Associate A Firebase Web Web" ، روی "ایجاد یک برنامه وب Firebase جدید" کلیک کنید.
- روی "پایان و استقرار" کلیک کنید. بعد از یک لحظه ، به صفحه جدیدی منتقل می شوید که می توانید وضعیت برنامه جدید میزبانی برنامه خود را با پشتیبانی کنید!
- پس از اتمام کار خود ، روی دامنه رایگان خود در زیر "دامنه ها" کلیک کنید. این ممکن است به دلیل انتشار DNS چند دقیقه طول بکشد.
- اوه اوه When you load the page, you'll see an error message that says "Application error: a server-side exception has occurred (see the server logs for more information)."
- In the Firebase console, check your App Hosting backend's "Logs" tab. You'll see an "Error: not implemented" log. We'll fix that in the next step when we add authentication.
You've deployed the initial web app! Every time you push a new commit to the main
branch of your GitHub repository, you'll see a new build and rollout begin in the Firebase console, and your site will automatically update once the rollout completes.
6. Add authentication to the web app
In this section, you add authentication to the web app so that you can log in to it.
Add an authorized domain
Firebase Authentication will only accept sign in requests from domains that you allow. Here, we'll add your App Hosting backend's domain to the list of approved domains in your project.
- Copy tour App Hosting backend's domain from the App Hosting "Overview" page.
- Go to the Auth Settings tab and choose Authorized Domains .
- Click the Add domain button.
- Enter your App Hosting backend's domain.
Implement the sign-in and sign-out functions
- In the
src/lib/firebase/auth.js
file, replace theonAuthStateChanged
,onIdTokenChanged
,signInWithGoogle
, andsignOut
functions with the following code:
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);
}
}
This code uses the following Firebase APIs:
Firebase API | توضیحات |
Adds an observer for changes to the user's sign-in state. | |
Adds an observer for changes to the user's ID token. | |
Creates a Google authentication provider instance. | |
Starts a dialog-based authentication flow. | |
Signs out the user. |
In the src/components/Header.jsx
file, the code already invokes the signInWithGoogle
and signOut
functions.
Send authentication state to the server
In order to pass authentication state to the server, we'll use cookies. Whenever the authentication state changes in the client, we'll update the __session
cookie.
In src/components/Header.jsx
, replace the useUserSession
function with the following code:
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;
}
Read authentication state on the server
We'll use FirebaseServerApp to mirror the client's authentication state on the server.
Open src/lib/firebase/serverApp.js
, and replace the getAuthenticatedAppForUser
function:
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 };
}
Verify changes
The root layout in the src/app/layout.js
file renders the header and passes in the user, if available, as a prop.
<Header initialUser={currentUser?.toJSON()} />
This means that the <Header>
component renders user data, if available, during server run time. If there are any authentication updates during the page lifecycle after initial page load, the onAuthStateChanged
handler handles them.
Now it's time to roll out a new build and verify what you built.
- Create a commit with commit message "Add authentication" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- Verify the new authentication behavior:
- In your browser, refresh the web app. Your display name appears in the header.
- Sign out and sign in again. You can repeat this step with different users.
- Optional: Right-click the web app, select View page source , and search for the display name. It appears in the raw HTML source returned from the server.
7. View restaurant information
The web app includes mock data for restaurants and reviews.
Add one or more restaurants
To insert mock restaurant data into your local Cloud Firestore database, follow these steps:
- Sign in to the web app if you haven't already. سپس، انتخاب کنید
> Add sample restaurants .
- In the Firebase console on the Firestore Database page, select restaurants . You see the top-level documents in the restaurant collection, each of which represents a restaurant.
- Click a few documents to explore the properties of a restaurant document.
Display the list of restaurants
Your Cloud Firestore database now has restaurants that the Next.js web app can display.
To define the data-fetching code, follow these steps:
- In the
src/app/page.js
file, find the<Home />
server component, and review the call to thegetRestaurants
function, which retrieves a list of restaurants at server run time. You implement thegetRestaurants
function in the following steps. - In the
src/lib/firebase/firestore.js
file, replace theapplyQueryFilters
andgetRestaurants
functions with the following code:
function applyQueryFilters(q, { category, city, price, sort }) {
if (category) {
q = query(q, where("category", "==", category));
}
if (city) {
q = query(q, where("city", "==", city));
}
if (price) {
q = query(q, where("price", "==", price.length));
}
if (sort === "Rating" || !sort) {
q = query(q, orderBy("avgRating", "desc"));
} else if (sort === "Review") {
q = query(q, orderBy("numRatings", "desc"));
}
return q;
}
export async function getRestaurants(db = db, filters = {}) {
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const results = await getDocs(q);
return results.docs.map((doc) => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
}
- Create a commit with commit message "Read the list of restaurants from Firestore" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- In the web app, refresh the page. Restaurant images appear as tiles on the page.
Verify that the restaurant listings load at server run time
Using the Next.js framework, it might not be obvious when data is loaded at server run time or client-side run time.
To verify that restaurant listings load at server run time, follow these steps:
- In the web app, open DevTools and disable JavaScript .
- Refresh the web app. The restaurant listings still load. Restaurant information is returned in the server response. When JavaScript is enabled, the restaurant information is hydrated through the client-side JavaScript code.
- In DevTools, re-enable JavaScript .
Listen for restaurant updates with Cloud Firestore snapshot listeners
In the previous section, you saw how the initial set of restaurants loaded from the src/app/page.js
file. The src/app/page.js
file is a server component and is rendered on the server, including the Firebase data-fetching code.
The src/components/RestaurantListings.jsx
file is a client component and can be configured to hydrate server-rendered markup.
To configure the src/components/RestaurantListings.jsx
file to hydrate server-rendered markup, follow these steps:
- In the
src/components/RestaurantListings.jsx
file, observe the following code, which is already written for you:
useEffect(() => {
return getRestaurantsSnapshot((data) => {
setRestaurants(data);
}, filters);
}, [filters]);
This code invokes the getRestaurantsSnapshot()
function, which is similar to the getRestaurants()
function that you implemented in a previous step. However this snapshot function provides a callback mechanism so that the callback is invoked every time a change is made to the restaurant's collection.
- In the
src/lib/firebase/firestore.js
file, replace thegetRestaurantsSnapshot()
function with the following code:
export function getRestaurantsSnapshot(cb, filters = {}) {
if (typeof cb !== "function") {
console.log("Error: The callback parameter is not a function");
return;
}
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
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);
});
}
Changes made through the Firestore Database page now reflect in the web app in real time.
- Create a commit with commit message "Listen for realtime restaurant updates" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- In the web app, select
> Add sample restaurants . If your snapshot function is implemented correctly, the restaurants appear in real-time without a page refresh.
8. Save user-submitted reviews from the web app
- In the
src/lib/firebase/firestore.js
file, replace theupdateWithRating()
function with the following code:
const updateWithRating = async (
transaction,
docRef,
newRatingDocument,
review
) => {
const restaurant = await transaction.get(docRef);
const data = restaurant.data();
const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
const newSumRating = (data?.sumRating || 0) + Number(review.rating);
const newAverage = newSumRating / newNumRatings;
transaction.update(docRef, {
numRatings: newNumRatings,
sumRating: newSumRating,
avgRating: newAverage,
});
transaction.set(newRatingDocument, {
...review,
timestamp: Timestamp.fromDate(new Date()),
});
};
This code inserts a new Firestore document representing the new review. The code also updates the existing Firestore document that represents the restaurant with updated figures for the number of ratings and the average calculated rating.
- Replace the
addReviewToRestaurant()
function with the following code:
export async function addReviewToRestaurant(db, restaurantId, review) {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!review) {
throw new Error("A valid review has not been provided.");
}
try {
const docRef = doc(collection(db, "restaurants"), restaurantId);
const newRatingDocument = doc(
collection(db, `restaurants/${restaurantId}/ratings`)
);
// corrected line
await runTransaction(db, transaction =>
updateWithRating(transaction, docRef, newRatingDocument, review)
);
} catch (error) {
console.error(
"There was an error adding the rating to the restaurant",
error
);
throw error;
}
}
Implement a Next.js Server Action
A Next.js Server Action provides a convenient API to access form data, such as data.get("text")
to get the text value from the form submission payload.
To use a Next.js Server Action to process the review form submission, follow these steps:
- In the
src/components/ReviewDialog.jsx
file, find theaction
attribute in the<form>
element.
<form action={handleReviewFormSubmission}>
The action
attribute value refers to a function that you implement in the next step.
- In the
src/app/actions.js
file, replace thehandleReviewFormSubmission()
function with the following code:
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
const { app } = await getAuthenticatedAppForUser();
const db = getFirestore(app);
await addReviewToRestaurant(db, data.get("restaurantId"), {
text: data.get("text"),
rating: data.get("rating"),
// This came from a hidden form field.
userId: data.get("userId"),
});
}
Add reviews for a restaurant
You implemented support for review submissions, so now you can verify that your reviews are inserted into Cloud Firestore correctly.
To add a review and verify that it's inserted into Cloud Firestore, follow these steps:
- Create a commit with commit message "Allow users to submit restaurant reviews" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- Refresh the web app, and select a restaurant from the home page.
- On the restaurant's page, click
.
- Select a star rating.
- یک بررسی بنویسید.
- روی ارسال کلیک کنید. Your review appears at the top of the list of reviews.
- In Cloud Firestore, search the Add document pane for the document of the restaurant that you reviewed and select it.
- In the Start collection pane, select ratings .
- In the Add document pane, find the document for your review to verify that it was inserted as expected.
9. Save user-uploaded files from the web app
In this section, you add functionality so that you can replace the image associated with a restaurant when you're logged in. You upload the image to Firebase Storage, and update the image URL in the Cloud Firestore document that represents the restaurant.
To save user-uploaded files from the web app, follow these steps:
- In the
src/components/Restaurant.jsx
file, observe the code that runs when the user uploads a file:
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 });
}
No changes are needed to this function, but you implement the behavior of the updateRestaurantImage()
function in the following steps.
- In the
src/lib/firebase/storage.js
file, replace theupdateRestaurantImage()
anduploadImage()
functions with the following code:
export async function updateRestaurantImage(restaurantId, image) {
try {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!image || !image.name) {
throw new Error("A valid image has not been provided.");
}
const publicImageUrl = await uploadImage(restaurantId, image);
await updateRestaurantImageReference(restaurantId, publicImageUrl);
return publicImageUrl;
} catch (error) {
console.error("Error processing request:", error);
}
}
async function uploadImage(restaurantId, image) {
const filePath = `images/${restaurantId}/${image.name}`;
const newImageRef = ref(storage, filePath);
await uploadBytesResumable(newImageRef, image);
return await getDownloadURL(newImageRef);
}
The updateRestaurantImageReference()
function is already implemented for you. This function updates an existing restaurant document in Cloud Firestore with an updated image URL.
Verify the image-upload functionality
To verify that the image uploads as expected, follow these steps:
- Create a commit with commit message "Allow users to change each restaurants' photo" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- In the web app, verify that you're logged in and select a restaurant.
- کلیک کنید
and upload an image from your filesystem. Your image leaves your local environment and is uploaded to Cloud Storage. The image appears immediately after you upload it.
- Navigate to Cloud Storage for Firebase.
- Navigate to the folder that represents the restaurant. The image that you uploaded exists in the folder.
10. Summarize restaurant reviews with generative ai
In this section, you'll add a review summary feature so that a user can quickly understand what everyone thinks of a restaurant without having to read every review.
Store a Gemini API key in Cloud Secret Manager
- To use the Gemini API, you'll need an API key. Visit Google AI Studio and click "Create API Key".
- In the "Search Google Cloud projects" input, choose your Firebase project. Every Firebase project is backed by a Google Cloud project.
- App Hosting integrates with Cloud Secret Manager to allow you to store sensitive values like API keys securely:
- In a terminal, run the command to create a new secret:
firebase apphosting:secrets:set GEMINI_API_KEY
- When prompted for the secret value, copy and paste your Gemini API key from Google AI Studio.
- When asked if the new secret is for production or local testing, choose "Production".
- When asked if you want to grant access so your backend's service account can access the secret, select "Yes".
- When asked if the new secret should be added to
apphosting.yaml
, enterY
to accept.
Your Gemini API key is now stored securely in Cloud Secret manager, and is accessible to your App Hosting backend.
Implement the review summary component
- In
src/components/Reviews/ReviewSummary.jsx
, replace theGeminiSummary
function with the following code: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>; } }
- Create a commit with commit message "Use AI to summarize reviews" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- Open a page for a restaurant. At the top, you should see a one-sentence summary of all the reviews on the page.
- Add a new review and refresh the page. You should see the summary change.
11. نتیجه گیری
تبریک می گویم! You learned how to use Firebase to add features and functionality to a Next.js app. Specifically, you used the following:
- Firebase App Hosting to automatically build and deploy your Next.js code every time you push to a configured branch.
- Firebase Authentication to enable sign-in and sign-out functionality.
- Cloud Firestore for restaurant data and restaurant review data.
- Cloud Storage for Firebase for restaurant images.
بیشتر بدانید
1. قبل از شروع
In this codelab, you'll learn how to integrate Firebase with a Next.js web app called Friendly Eats, which is a website for restaurant reviews.
The completed web app offers useful features that demonstrate how Firebase can help you build Next.js apps. این ویژگی ها شامل موارد زیر است:
- Automatic build and deploy: This codelab uses Firebase App Hosting to automatically build and deploy your Next.js code every time you push to a configured branch.
- Sign-in and sign-out: The completed web app lets you sign in with Google and sign out. User login and persistence is managed entirely through Firebase Authentication .
- Images: The completed web app lets signed-in users upload restaurant images. Image assets are stored in Cloud Storage for Firebase . The Firebase JavaScript SDK provides a public URL to uploaded images. This public URL is then stored in the relevant restaurant document in Cloud Firestore .
- Reviews: The completed web app lets signed-in users post reviews of restaurants that consist of a star rating and a text-based message. Review information is stored in Cloud Firestore.
- Filters: The completed web app lets signed-in users filter the list of restaurants based on category, location, and price. You can also customize the sorting method used. Data is accessed from Cloud Firestore, and Firestore queries are applied based on the filters used.
پیش نیازها
- یک حساب GitHub
- Knowledge of Next.js and JavaScript
چیزی که یاد خواهید گرفت
- How to use Firebase with the Next.js App Router and server-side rendering.
- How to persist images in Cloud Storage for Firebase.
- How to read and write data in a Cloud Firestore database.
- How to use sign-in with Google with the Firebase JavaScript SDK.
آنچه شما نیاز دارید
- Git
- A recent stable version of Node.js
- A browser of your choice, such as Google Chrome
- A development environment with a code editor and terminal
- A Google account for the creation and management of your Firebase project
- The ability to upgrade your Firebase project to the Blaze pricing plan
2. Set up your development environment and GitHub repository
This codelab provides the app's starter codebase and relies on the Firebase CLI.
یک مخزن GitHub ایجاد کنید
The codelab source can be found at https://github.com/firebase/friendlyeats-web . The repository contains sample projects for multiple platforms. However, this codelab uses only the nextjs-start
directory. Take note of the following directories:
* `nextjs-start`: contains the starter code upon which you build.
* `nextjs-end`: contains the solution code for the finished web app.
Copy the nextjs-start
folder into your own repository:
- Using a terminal, create a new folder on your computer and change into the new directory:
mkdir codelab-friendlyeats-web cd codelab-friendlyeats-web
- Use the giget npm package to fetch only the
nextjs-start
folder:npx giget@latest gh:firebase/friendlyeats-web/nextjs-start#master . --install
- Track changes locally with git:
git init git add . git commit -m "codelab starting point" git branch -M main
- Create a new GitHub repository: https://github.com/new . Name it anything you'd like.
- Copy the new URL that GitHub creates for you. It will look like one of the following:
-
https://github.com/<USER_NAME>/<REPOSITORY_NAME>.git
or -
git@github.com:<USER_NAME>/<REPOSITORY_NAME>.git
-
- Push local changes to your new GitHub repository by running the following command. Substitute your actual repository URL for the
<REPOSITORY_URL>
placeholder.git remote add origin <REPOSITORY_URL> git push -u origin main
- You should now see the starter code in your GitHub repository.
Install or update the Firebase CLI
Run the following command to verify that you have the Firebase CLI installed and that it's v14.1.0 or higher:
firebase --version
If you see a lower version or you don't have the Firebase CLI installed, run the install command:
npm install -g firebase-tools@latest
If you're unable to install the Firebase CLI because of permission errors, see the npm documentation or use another installation option .
Log in to Firebase
- Run the following command to log in to the Firebase CLI:
firebase login
- Depending on whether you want Firebase to collect data, enter
Y
orN
. - In your browser, select your Google account, and then click Allow .
3. Set up your Firebase project
In this section, you'll set up a Firebase project and associate a Firebase web app with it. You'll also set up the Firebase services used by the sample web app.
یک پروژه Firebase ایجاد کنید
- In the Firebase console , click Add project .
- In the Enter your project name text box, enter
FriendlyEats Codelab
(or a project name of your choice), and then click Continue . - For this codelab, you don't need Google Analytics, so toggle off the Enable Google Analytics for this project option.
- روی ایجاد پروژه کلیک کنید.
- Wait for your project to provision, and then click Continue .
- In your Firebase project, go to Project Settings . Note your project ID because you need it later. This unique identifier is how your project is identified (for example, in the Firebase CLI).
Upgrade your Firebase pricing plan
To use Firebase App Hosting and Cloud Storage for Firebase, your Firebase project needs to be on the pay-as-you go (Blaze) pricing plan , which means it's linked to a Cloud Billing account .
- A Cloud Billing account requires a payment method, like a credit card.
- If you're new to Firebase and Google Cloud, check if you're eligible for a $300 credit and a Free Trial Cloud Billing account .
- If you're doing this codelab as part of an event, ask your organizer if there are any Cloud credits available.
To upgrade your project to the Blaze plan, follow these steps:
- In the Firebase console, select to upgrade your plan .
- Select the Blaze plan. Follow the on-screen instructions to link a Cloud Billing account to your project.
If you needed to create a Cloud Billing account as part of this upgrade, you might need to navigate back to the upgrade flow in the Firebase console to complete the upgrade.
Add a web app to your Firebase project
- Navigate to your Project overview in your Firebase project, and then click
وب
If you already have apps registered in your project, click Add app to see the Web icon. - In the App nickname text box, enter a memorable app nickname, such as
My Next.js app
. - Keep the Also set up Firebase Hosting for this app checkbox unchecked.
- Click Register app > Continue to console .
Set up Firebase services in the Firebase console
Set up Authentication
- In the Firebase console, navigate to Authentication .
- روی Get start کلیک کنید.
- In the Additional providers column, click Google > Enable .
- In the Public-facing name for project text box, enter a memorable name, such as
My Next.js app
. - From the Support email for project drop-down, select your email address.
- روی ذخیره کلیک کنید.
Set up Cloud Firestore
- In the left-panel of the Firebase console, expand Build and then select Firestore Database .
- روی ایجاد پایگاه داده کلیک کنید.
- Leave the Database ID set to
(default)
. - Select a location for your database, then click Next .
For a real app, you want to choose a location that's close to your users. - Click Start in test mode . Read the disclaimer about the security rules.
Later in this codelab, you'll add Security Rules to secure your data. Do not distribute or expose an app publicly without adding Security Rules for your database. - روی ایجاد کلیک کنید.
Set up Cloud Storage for Firebase
- In the left-panel of the Firebase console, expand Build and then select Storage .
- روی Get start کلیک کنید.
- Select a location for your default Storage bucket.
Buckets inUS-WEST1
,US-CENTRAL1
, andUS-EAST1
can take advantage of the "Always Free" tier for Google Cloud Storage. Buckets in all other locations follow Google Cloud Storage pricing and usage . - Click Start in test mode . Read the disclaimer about the security rules.
Later in this codelab, you'll add security rules to secure your data. Do not distribute or expose an app publicly without adding Security Rules for your Storage bucket. - روی ایجاد کلیک کنید.
Deploy Security Rules
The code already has sets of security rules for Firestore and for Cloud Storage for Firebase. After you deploy the Security Rules, the data in your database and your bucket are better protected from misuse.
- In your terminal, configure the CLI to use the Firebase project you created earlier:
When prompted for an alias, enterfirebase use --add
friendlyeats-codelab
. - To deploy these Security Rules, run this command in your terminal:
firebase deploy --only firestore:rules,storage
- If you're asked:
"Cloud Storage for Firebase needs an IAM Role to use cross-service rules. Grant the new role?"
, pressEnter
to select Yes .
4. Review the starter codebase
In this section, you'll review a few areas of the app's starter codebase to which you'll add functionality in this codelab.
Folder and file structure
The following table contains an overview of the folder and file structure of the app:
پوشه ها و فایل ها | توضیحات |
| React components for filters, headers, restaurant details, and reviews |
| Utility functions that aren't necessarily bound to React or Next.js |
| Firebase-specific code and Firebase configuration |
| Static assets in the web app, like icons |
| Routing with the Next.js App Router |
| Project dependencies with npm |
| Next.js-specific configuration (server actions are enabled ) |
| JavaScript language-service configuration |
Server and client components
The app is a Next.js web app that uses the App Router . Server rendering is used throughout the app. For example, the src/app/page.js
file is a server component responsible for the main page. The src/components/RestaurantListings.jsx
file is a client component denoted by the "use client"
directive at the beginning of the file.
بیانیه های وارداتی
You might notice import statements like the following:
import RatingPicker from "@/src/components/RatingPicker.jsx";
The app uses the @
symbol to avoid clunky relative import paths and is made possible by path aliases .
Firebase-specific APIs
All Firebase API code is wrapped in the src/lib/firebase
directory. Individual React components then import the wrapped functions from the src/lib/firebase
directory, rather than importing Firebase functions directly.
داده های ساختگی
Mock restaurant and review data is contained in the src/lib/randomData.js
file. Data from that file is assembled in the code in the src/lib/fakeRestaurants.js
file.
5. Create an App Hosting backend
In this section, you'll set up an App Hosting backend to watch a branch on your git repository.
By the end of this section, you'll have an App Hosting backend connected to your repository in GitHub that will automatically re-build and roll out a new version of your app whenever you push a new commit to your main
branch.
یک Backend ایجاد کنید
- Navigate to the App Hosting page in the Firebase console:
- Click "Get started" to start the backend creation flow. Configure your backend as follows:
- یک منطقه را انتخاب کنید. For a real app, you'd choose the region closest to your users.
- Follow the prompts in the "Import a GitHub repository" step to connect the GitHub repository you created earlier.
- Set deployment settings:
- Keep the root directory as
/
- Set the live branch to
main
- Enable automatic rollouts
- Keep the root directory as
- Name your backend
friendlyeats-codelab
. - In "Associate a Firebase web app", click "Create a new Firebase web app".
- Click "Finish and deploy". After a moment, you'll be taken to a new page where you can see the status of your new App Hosting backend!
- Once your rollout completes, click your free domain under "domains". This may take a few minutes to begin working due to DNS propagation.
- اوه اوه When you load the page, you'll see an error message that says "Application error: a server-side exception has occurred (see the server logs for more information)."
- In the Firebase console, check your App Hosting backend's "Logs" tab. You'll see an "Error: not implemented" log. We'll fix that in the next step when we add authentication.
You've deployed the initial web app! Every time you push a new commit to the main
branch of your GitHub repository, you'll see a new build and rollout begin in the Firebase console, and your site will automatically update once the rollout completes.
6. Add authentication to the web app
In this section, you add authentication to the web app so that you can log in to it.
Add an authorized domain
Firebase Authentication will only accept sign in requests from domains that you allow. Here, we'll add your App Hosting backend's domain to the list of approved domains in your project.
- Copy tour App Hosting backend's domain from the App Hosting "Overview" page.
- Go to the Auth Settings tab and choose Authorized Domains .
- Click the Add domain button.
- Enter your App Hosting backend's domain.
Implement the sign-in and sign-out functions
- In the
src/lib/firebase/auth.js
file, replace theonAuthStateChanged
,onIdTokenChanged
,signInWithGoogle
, andsignOut
functions with the following code:
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);
}
}
This code uses the following Firebase APIs:
Firebase API | توضیحات |
Adds an observer for changes to the user's sign-in state. | |
Adds an observer for changes to the user's ID token. | |
Creates a Google authentication provider instance. | |
Starts a dialog-based authentication flow. | |
Signs out the user. |
In the src/components/Header.jsx
file, the code already invokes the signInWithGoogle
and signOut
functions.
Send authentication state to the server
In order to pass authentication state to the server, we'll use cookies. Whenever the authentication state changes in the client, we'll update the __session
cookie.
In src/components/Header.jsx
, replace the useUserSession
function with the following code:
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;
}
Read authentication state on the server
We'll use FirebaseServerApp to mirror the client's authentication state on the server.
Open src/lib/firebase/serverApp.js
, and replace the getAuthenticatedAppForUser
function:
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 };
}
Verify changes
The root layout in the src/app/layout.js
file renders the header and passes in the user, if available, as a prop.
<Header initialUser={currentUser?.toJSON()} />
This means that the <Header>
component renders user data, if available, during server run time. If there are any authentication updates during the page lifecycle after initial page load, the onAuthStateChanged
handler handles them.
Now it's time to roll out a new build and verify what you built.
- Create a commit with commit message "Add authentication" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- Verify the new authentication behavior:
- In your browser, refresh the web app. Your display name appears in the header.
- Sign out and sign in again. You can repeat this step with different users.
- Optional: Right-click the web app, select View page source , and search for the display name. It appears in the raw HTML source returned from the server.
7. View restaurant information
The web app includes mock data for restaurants and reviews.
Add one or more restaurants
To insert mock restaurant data into your local Cloud Firestore database, follow these steps:
- Sign in to the web app if you haven't already. سپس، انتخاب کنید
> Add sample restaurants .
- In the Firebase console on the Firestore Database page, select restaurants . You see the top-level documents in the restaurant collection, each of which represents a restaurant.
- Click a few documents to explore the properties of a restaurant document.
Display the list of restaurants
Your Cloud Firestore database now has restaurants that the Next.js web app can display.
To define the data-fetching code, follow these steps:
- In the
src/app/page.js
file, find the<Home />
server component, and review the call to thegetRestaurants
function, which retrieves a list of restaurants at server run time. You implement thegetRestaurants
function in the following steps. - In the
src/lib/firebase/firestore.js
file, replace theapplyQueryFilters
andgetRestaurants
functions with the following code:
function applyQueryFilters(q, { category, city, price, sort }) {
if (category) {
q = query(q, where("category", "==", category));
}
if (city) {
q = query(q, where("city", "==", city));
}
if (price) {
q = query(q, where("price", "==", price.length));
}
if (sort === "Rating" || !sort) {
q = query(q, orderBy("avgRating", "desc"));
} else if (sort === "Review") {
q = query(q, orderBy("numRatings", "desc"));
}
return q;
}
export async function getRestaurants(db = db, filters = {}) {
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
const results = await getDocs(q);
return results.docs.map((doc) => {
return {
id: doc.id,
...doc.data(),
// Only plain objects can be passed to Client Components from Server Components
timestamp: doc.data().timestamp.toDate(),
};
});
}
- Create a commit with commit message "Read the list of restaurants from Firestore" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- In the web app, refresh the page. Restaurant images appear as tiles on the page.
Verify that the restaurant listings load at server run time
Using the Next.js framework, it might not be obvious when data is loaded at server run time or client-side run time.
To verify that restaurant listings load at server run time, follow these steps:
- In the web app, open DevTools and disable JavaScript .
- Refresh the web app. The restaurant listings still load. Restaurant information is returned in the server response. When JavaScript is enabled, the restaurant information is hydrated through the client-side JavaScript code.
- In DevTools, re-enable JavaScript .
Listen for restaurant updates with Cloud Firestore snapshot listeners
In the previous section, you saw how the initial set of restaurants loaded from the src/app/page.js
file. The src/app/page.js
file is a server component and is rendered on the server, including the Firebase data-fetching code.
The src/components/RestaurantListings.jsx
file is a client component and can be configured to hydrate server-rendered markup.
To configure the src/components/RestaurantListings.jsx
file to hydrate server-rendered markup, follow these steps:
- In the
src/components/RestaurantListings.jsx
file, observe the following code, which is already written for you:
useEffect(() => {
return getRestaurantsSnapshot((data) => {
setRestaurants(data);
}, filters);
}, [filters]);
This code invokes the getRestaurantsSnapshot()
function, which is similar to the getRestaurants()
function that you implemented in a previous step. However this snapshot function provides a callback mechanism so that the callback is invoked every time a change is made to the restaurant's collection.
- In the
src/lib/firebase/firestore.js
file, replace thegetRestaurantsSnapshot()
function with the following code:
export function getRestaurantsSnapshot(cb, filters = {}) {
if (typeof cb !== "function") {
console.log("Error: The callback parameter is not a function");
return;
}
let q = query(collection(db, "restaurants"));
q = applyQueryFilters(q, filters);
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);
});
}
Changes made through the Firestore Database page now reflect in the web app in real time.
- Create a commit with commit message "Listen for realtime restaurant updates" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- In the web app, select
> Add sample restaurants . If your snapshot function is implemented correctly, the restaurants appear in real-time without a page refresh.
8. Save user-submitted reviews from the web app
- In the
src/lib/firebase/firestore.js
file, replace theupdateWithRating()
function with the following code:
const updateWithRating = async (
transaction,
docRef,
newRatingDocument,
review
) => {
const restaurant = await transaction.get(docRef);
const data = restaurant.data();
const newNumRatings = data?.numRatings ? data.numRatings + 1 : 1;
const newSumRating = (data?.sumRating || 0) + Number(review.rating);
const newAverage = newSumRating / newNumRatings;
transaction.update(docRef, {
numRatings: newNumRatings,
sumRating: newSumRating,
avgRating: newAverage,
});
transaction.set(newRatingDocument, {
...review,
timestamp: Timestamp.fromDate(new Date()),
});
};
This code inserts a new Firestore document representing the new review. The code also updates the existing Firestore document that represents the restaurant with updated figures for the number of ratings and the average calculated rating.
- Replace the
addReviewToRestaurant()
function with the following code:
export async function addReviewToRestaurant(db, restaurantId, review) {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!review) {
throw new Error("A valid review has not been provided.");
}
try {
const docRef = doc(collection(db, "restaurants"), restaurantId);
const newRatingDocument = doc(
collection(db, `restaurants/${restaurantId}/ratings`)
);
// corrected line
await runTransaction(db, transaction =>
updateWithRating(transaction, docRef, newRatingDocument, review)
);
} catch (error) {
console.error(
"There was an error adding the rating to the restaurant",
error
);
throw error;
}
}
Implement a Next.js Server Action
A Next.js Server Action provides a convenient API to access form data, such as data.get("text")
to get the text value from the form submission payload.
To use a Next.js Server Action to process the review form submission, follow these steps:
- In the
src/components/ReviewDialog.jsx
file, find theaction
attribute in the<form>
element.
<form action={handleReviewFormSubmission}>
The action
attribute value refers to a function that you implement in the next step.
- In the
src/app/actions.js
file, replace thehandleReviewFormSubmission()
function with the following code:
// This is a next.js server action, which is an alpha feature, so
// use with caution.
// https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
export async function handleReviewFormSubmission(data) {
const { app } = await getAuthenticatedAppForUser();
const db = getFirestore(app);
await addReviewToRestaurant(db, data.get("restaurantId"), {
text: data.get("text"),
rating: data.get("rating"),
// This came from a hidden form field.
userId: data.get("userId"),
});
}
Add reviews for a restaurant
You implemented support for review submissions, so now you can verify that your reviews are inserted into Cloud Firestore correctly.
To add a review and verify that it's inserted into Cloud Firestore, follow these steps:
- Create a commit with commit message "Allow users to submit restaurant reviews" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- Refresh the web app, and select a restaurant from the home page.
- On the restaurant's page, click
.
- Select a star rating.
- یک بررسی بنویسید.
- روی ارسال کلیک کنید. Your review appears at the top of the list of reviews.
- In Cloud Firestore, search the Add document pane for the document of the restaurant that you reviewed and select it.
- In the Start collection pane, select ratings .
- In the Add document pane, find the document for your review to verify that it was inserted as expected.
9. Save user-uploaded files from the web app
In this section, you add functionality so that you can replace the image associated with a restaurant when you're logged in. You upload the image to Firebase Storage, and update the image URL in the Cloud Firestore document that represents the restaurant.
To save user-uploaded files from the web app, follow these steps:
- In the
src/components/Restaurant.jsx
file, observe the code that runs when the user uploads a file:
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 });
}
No changes are needed to this function, but you implement the behavior of the updateRestaurantImage()
function in the following steps.
- In the
src/lib/firebase/storage.js
file, replace theupdateRestaurantImage()
anduploadImage()
functions with the following code:
export async function updateRestaurantImage(restaurantId, image) {
try {
if (!restaurantId) {
throw new Error("No restaurant ID has been provided.");
}
if (!image || !image.name) {
throw new Error("A valid image has not been provided.");
}
const publicImageUrl = await uploadImage(restaurantId, image);
await updateRestaurantImageReference(restaurantId, publicImageUrl);
return publicImageUrl;
} catch (error) {
console.error("Error processing request:", error);
}
}
async function uploadImage(restaurantId, image) {
const filePath = `images/${restaurantId}/${image.name}`;
const newImageRef = ref(storage, filePath);
await uploadBytesResumable(newImageRef, image);
return await getDownloadURL(newImageRef);
}
The updateRestaurantImageReference()
function is already implemented for you. This function updates an existing restaurant document in Cloud Firestore with an updated image URL.
Verify the image-upload functionality
To verify that the image uploads as expected, follow these steps:
- Create a commit with commit message "Allow users to change each restaurants' photo" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- In the web app, verify that you're logged in and select a restaurant.
- کلیک کنید
and upload an image from your filesystem. Your image leaves your local environment and is uploaded to Cloud Storage. The image appears immediately after you upload it.
- Navigate to Cloud Storage for Firebase.
- Navigate to the folder that represents the restaurant. The image that you uploaded exists in the folder.
10. Summarize restaurant reviews with generative ai
In this section, you'll add a review summary feature so that a user can quickly understand what everyone thinks of a restaurant without having to read every review.
Store a Gemini API key in Cloud Secret Manager
- To use the Gemini API, you'll need an API key. Visit Google AI Studio and click "Create API Key".
- In the "Search Google Cloud projects" input, choose your Firebase project. Every Firebase project is backed by a Google Cloud project.
- App Hosting integrates with Cloud Secret Manager to allow you to store sensitive values like API keys securely:
- In a terminal, run the command to create a new secret:
firebase apphosting:secrets:set GEMINI_API_KEY
- When prompted for the secret value, copy and paste your Gemini API key from Google AI Studio.
- When asked if the new secret is for production or local testing, choose "Production".
- When asked if you want to grant access so your backend's service account can access the secret, select "Yes".
- When asked if the new secret should be added to
apphosting.yaml
, enterY
to accept.
Your Gemini API key is now stored securely in Cloud Secret manager, and is accessible to your App Hosting backend.
Implement the review summary component
- In
src/components/Reviews/ReviewSummary.jsx
, replace theGeminiSummary
function with the following code: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>; } }
- Create a commit with commit message "Use AI to summarize reviews" and push it to your GitHub repository.
- Open the App Hosting page in the Firebase console and wait for your new rollout to complete.
- Open a page for a restaurant. At the top, you should see a one-sentence summary of all the reviews on the page.
- Add a new review and refresh the page. You should see the summary change.
11. نتیجه گیری
تبریک می گویم! You learned how to use Firebase to add features and functionality to a Next.js app. Specifically, you used the following:
- Firebase App Hosting to automatically build and deploy your Next.js code every time you push to a configured branch.
- Firebase Authentication to enable sign-in and sign-out functionality.
- Cloud Firestore for restaurant data and restaurant review data.
- Cloud Storage for Firebase for restaurant images.