אם עבדתם עם Firebase JS SDK או עם ערכות SDK אחרות של לקוחות Firebase, סביר להניח שאתם מכירים את הממשק FirebaseApp ואת אופן השימוש בו כדי להגדיר מופעי אפליקציות. כדי לאפשר פעולות דומות בצד השרת, Firebase מספק את FirebaseServerApp.
FirebaseServerApp היא גרסה של FirebaseApp לשימוש בסביבות של עיבוד בצד השרת (SSR). הוא כולל כלים להמשך סשנים ב-Firebase שכוללים עיבוד בצד הלקוח (CSR) ועיבוד בצד השרת (SSR). הכלים והאסטרטגיות האלה יכולים לעזור לשפר אפליקציות אינטרנט דינמיות שנוצרו באמצעות Firebase ונפרסו בסביבות של Google כמו Firebase App Hosting.
השתמש בFirebaseServerApp כדי:
- להריץ קוד בצד השרת בהקשר של המשתמש, בניגוד ל-SDK של Firebase לאדמינים שיש לו הרשאות ניהול מלאות.
- הפעלת השימוש ב-App Check בסביבות SSR.
- להמשיך סשן של Firebase Auth שנוצר בלקוח.
מחזור החיים של FirebaseServerApp
מסגרות של עיבוד בצד השרת (SSR) וסביבות זמן ריצה אחרות שאינן דפדפן, כמו עובדים בענן, מבצעות אופטימיזציה של זמן האתחול על ידי שימוש חוזר במשאבים בכמה הפעלות. FirebaseServerApp מיועד לסביבות כאלה, ומשתמש במנגנון ספירת הפניות. אם אפליקציה מפעילה את initializeServerApp עם אותם פרמטרים כמו initializeServerApp קודם, היא מקבלת את אותו מופע של FirebaseServerApp שכבר אותחל. כך אפשר לצמצם את התקורה המיותרת של האתחול ואת הקצאות הזיכרון. כשמפעילים את deleteApp במופע של FirebaseServerApp, מספר ההפניות מצטמצם, והמופע משתחרר אחרי שמספר ההפניות מגיע לאפס.
ניקוי של FirebaseServerApp מופעים
יכול להיות שיהיה קשה לדעת מתי להפעיל את deleteApp במכונה של FirebaseServerApp, במיוחד אם מפעילים הרבה פעולות אסינכרוניות במקביל. השדה releaseOnDeref של FirebaseServerAppSettings עוזר לפשט את התהליך. אם מקצים ל-releaseOnDeref הפניה לאובייקט עם משך החיים של היקף הבקשה (לדוגמה, אובייקט הכותרות של בקשת ה-SSR), הערך של FirebaseServerApp יקטין את מספר ההפניות שלו כשהמסגרת תחזיר את אובייקט הכותרת. הפעולה הזו מנקה באופן אוטומטי את המכונה של FirebaseServerApp.
דוגמה לשימוש ב-releaseOnDeref:
/// Next.js
import { headers } from 'next/headers'
import { FirebaseServerAppSettings, initializeServerApp} from "firebase/app";
export default async function Page() {
const headersObj = await headers();
let appSettings: FirebaseServerAppSettings = {};
appSettings.releaseOnDeref = headersObj;
const serverApp = initializeServerApp(firebaseConfig, appSettings);
...
}
המשך סשנים מאומתים שנוצרו אצל הלקוח
כשמאתחלים מופע של FirebaseServerApp באמצעות טוקן של מזהה אימות, אפשר לגשר על סשנים של משתמשים מאומתים בין סביבות של עיבוד בצד הלקוח (CSR) ועיבוד בצד השרת (SSR). מופעים של Firebase Auth SDK שמאותחלים עם אובייקט FirebaseServerApp שמכיל טוקן של מזהה Auth ינסו להכניס את המשתמש לחשבון בזמן האתחול, בלי שהאפליקציה תצטרך להפעיל שיטות כניסה לחשבון.
כשמספקים טוקן של מזהה אימות, האפליקציות יכולות להשתמש בכל אחת משיטות ההתחברות של Auth בצד הלקוח, וכך הסשן ממשיך בצד השרת, גם בשיטות ההתחברות שדורשות אינטראקציית משתמש. בנוסף, הוא מאפשר להעביר פעולות אינטנסיביות לשרת, כמו שאילתות Firestore מאומתות, מה שמשפר את ביצועי הרינדור של האפליקציה.
/// Next.js
import { initializeServerApp } from "firebase/app";
import { getAuth } from "firebase/auth";
// Replace the following with your app's
// Firebase project configuration
const firebaseConfig = {
// ...
};
const firebaseServerAppSettings = {
authIdToken: token // See "Pass client tokens to the server side
// rendering phase" for an example on how transmit
// the token from the client and the server.
}
const serverApp =
initializeServerApp(firebaseConfig,
firebaseServerAppSettings);
const serverAuth = getAuth(serverApp);
// FirebaseServerApp and Auth will now attempt
// to sign in the current user based on provided
// authIdToken.
שימוש ב-App Check בסביבות SSR
אכיפת App Check מסתמכת על מכונה של App Check SDK שערכות Firebase SDK משתמשות בה כדי לבצע קריאה פנימית ל-getToken. האסימון שנוצר נכלל בבקשות לכל שירותי Firebase, וכך הקצה העורפי יכול לאמת את האפליקציה.
עם זאת, מכיוון ש-App Check SDK צריך דפדפן כדי לגשת להיוריסטיקה ספציפית לאימות האפליקציה, אי אפשר להפעיל אותו בסביבות שרת.
FirebaseServerApp מספקת חלופה. אם מספקים טוקן של App Check שנוצר על ידי הלקוח במהלך האתחול של FirebaseServerApp, ערכות ה-SDK של מוצרי Firebase ישתמשו בו כשהן יפעילו את שירותי Firebase, ולא יהיה צורך במופע של App Check SDK.
/// Next.js
import { initializeServerApp } from "firebase/app";
// Replace the following with your app's
// Firebase project configuration
const firebaseConfig = {
// ...
};
const firebaseServerAppSettings = {
appCheckToken: token // See "Pass client tokens to the server side
// rendering phase" for an example on how transmit
// the token from the client and the server.
}
const serverApp =
initializeServerApp(firebaseConfig,
firebaseServerAppSettings);
// The App Check token will now be appended to all Firebase service requests.
העברת אסימוני לקוח לשלב העיבוד בצד השרת
כדי להעביר טוקנים של מזהה אימות מאומתים (ואסימוני App Check) מהלקוח לשלב העיבוד בצד השרת (SSR), צריך להשתמש ב-Service Worker. בגישה הזו, צריך ליירט בקשות אחזור שמפעילות SSR ולהוסיף את האסימונים לכותרות הבקשה.
במאמר ניהול סשנים באמצעות service workers מוסבר איך להטמיע service worker של Firebase Auth. בקטע שינויים בצד השרת יש קוד שמדגים איך לנתח את האסימונים האלה מהכותרות כדי להשתמש בהם באתחול של FirebaseServerApp.
שימוש ב-Firestore בסביבות SSR
כשמפתחים אפליקציות אינטרנט עם עיבוד בצד השרת (SSR), בדרך כלל צריך לשתף נתונים בין השרת ללקוח כדי לשפר את הביצועים ואת חוויית המשתמש. ערכת ה-SDK של Firestore מספקת כלי סריאליזציה שמאפשרים לצלם תמונות מצב וסוגי נתונים ספציפיים בשרת ולהעביר אותם ישירות לרכיבים בצד הלקוח. התהליך הזה מבטל אחזורים מיותרים, כי הוא מאפשר ללקוח להוסיף נתונים למצב באמצעות הנתונים שאוחזרו מראש בשלב ה-SSR. בנוסף, אתם יכולים לעבור מהמצבים האלה שעברו סריאליזציה למאזינים בזמן אמת, כדי לוודא שהאפליקציה תישאר מסונכרנת עם מסד הנתונים.
בקטע הזה מוסבר איך להשתמש מחדש בנתונים שאוחזרו במהלך שלב העיבוד בצד השרת (SSR) ברכיבים בצד הלקוח.
סוגי נתונים של סריאליזציה
סוגי נתונים מסוימים של Firestore מספקים שיטת toJSON להמרת הנתונים שלהם לפורמט שניתן לסדרתיות. הם כוללים מופעים של אובייקטים כמו Bytes, GeoPoint, Timestamp ו-VectorValue.
אחרי שהנתונים בפורמט JSON, אפשר להעביר אותם מהשרת ללקוח באמצעות מנגנוני מסגרת סטנדרטיים, או כפרמטרים לרכיבים שמשתרעים על פני החלוקה. לדוגמה:
import {
Bytes
} from 'firebase/firestore';
const BYTES_DATA = new Uint8Array([0, 1, 2, 3, 4, 5]);
const bytes = Bytes.fromUint8Array(BYTES_DATA);
const bytesJSON = bytes.toJSON();
ביטול ההמרה של סוגי נתונים
סוגי הנתונים של Firestore כוללים את השיטה הסטטית fromJSON כדי להמיר את הנתונים שעברו סריאליזציה לסוג נתונים של Firestore שניתן להפעיל.
לדוגמה, הקוד הבא מבטל את ההמרה לסדרה של סוג הנתונים Bytes:
import {
Bytes
} from 'firebase/firestore';
// Assuming the same `bytesJSON` variable from the previous example.
const deserializedBytes = Bytes.fromJSON(bytesJSON);
סריאליזציה ודה-סריאליזציה של תמונות מצב ב-Firestore
בדומה לסוגי הנתונים של Firestore, אפשר להעביר מופעים של DocumentSnapshot ו-QuerySnapshot באמצעות toJSON. עם זאת, כדי לבטל את הסריאליזציה שלהם, צריך להשתמש בפונקציות העצמאיות documentSnapshotFromJSON ו-querySnapshotFromJSON במקום בשיטה הסטטית fromJSON.
לדוגמה, אפשר להשתמש ב-toJSON כדי להמיר את התוצאות של querySnapshot בפעולה של query:
import {
collection,
getDocs,
query,
querySnapshotFromJSON
} from 'firebase/firestore';
// Assuming a configured instance of Firestore in the variable `firestore`.
const queryRef = query(collection(firestore, QUERY_PATH));
const querySnapshot = await getDocs(queryRef);
const querySnapshotJson = querySnapshot.toJSON();
לאחר מכן, אפשר לבטל את ההמרה של הנתונים האלה:
import {
querySnapshotFromJSON
} from 'firebase/firestore';
// deserializedSnapshot is an object of type QuerySnapshot:
const deserializedSnapshot =
querySnapshotFromJSON(firestore, querySnapshotJson);
מאזינים עם תמונות מצב בסדרה
למרות שהנתונים שנשלפים במהלך שלב ה-SSR חשובים לעיבוד הראשוני של ה-CSR, יכול להיות שעדיין תצטרכו לעקוב אחרי שירות Firestore כדי לקבל עדכונים בזמן אמת למידע הזה.
אם האפליקציה שלכם דורשת את העדכונים האלה בזמן אמת, אתם יכולים להשתמש בפונקציה onSnapshotResume כדי להפעיל את SnapshotListener של Firestore עם נתוני Snapshot שעברו סריאליזציה. לדוגמה:
const observer = {
next: (qs) => {
console.log("onSnapshot invoked: ", qs.data());
},
error: (e) => {
console.log("error callback invoked: ", e.toString());
}
};
const unsubscribe = onSnapshotResume(firestore, querySnapshotJson, observer);