استفاده از Firebase در برنامه های وب پویا با SSR (رندر سمت سرور)، استفاده از Firebase در برنامه های وب پویا با SSR (رندر سمت سرور)، استفاده از Firebase در برنامه های وب پویا با SSR (رندر سمت سرور)

اگر با Firebase JS SDK یا سایر SDK های کلاینت Firebase کار کرده باشید، احتمالاً با رابط FirebaseApp و نحوه استفاده از آن برای پیکربندی نمونه‌های برنامه آشنا هستید. برای تسهیل عملیات مشابه در سمت سرور، Firebase FirebaseServerApp را ارائه می‌دهد.

FirebaseServerApp نوعی از FirebaseApp برای استفاده در محیط‌های رندر سمت سرور (SSR) است. این برنامه شامل ابزارهایی برای ادامه جلسات Firebase است که فاصله رندر سمت کلاینت (CSR) / رندر سمت سرور را پوشش می‌دهد. این ابزارها و استراتژی‌ها می‌توانند به بهبود برنامه‌های وب پویا که با Firebase ساخته شده‌اند و در محیط‌های Google مانند Firebase App Hosting مستقر شده‌اند، کمک کنند.

از FirebaseServerApp برای موارد زیر استفاده کنید:

  • کد سمت سرور را در چارچوب کاربر اجرا می‌کند، برخلاف Firebase Admin SDK که دارای حقوق مدیریتی کامل است.
  • استفاده از App Check را در محیط‌های SSR فعال کنید.
  • ادامه دادن یک جلسه احراز هویت Firebase که در کلاینت ایجاد شده است.

چرخه حیات FirebaseServerApp

چارچوب‌های رندر سمت سرور (SSR) و سایر زمان‌های اجرای غیر مرورگر مانند کارگران ابری، با استفاده مجدد از منابع در چندین اجرا، زمان اولیه‌سازی را بهینه می‌کنند. FirebaseServerApp برای تطبیق با این محیط‌ها با استفاده از مکانیسم شمارش مرجع طراحی شده است. اگر یک برنامه initializeServerApp با پارامترهای مشابه initializeServerApp قبلی فراخوانی کند، همان نمونه FirebaseServerApp را که قبلاً مقداردهی اولیه شده است، دریافت می‌کند. این امر سربار اولیه‌سازی غیرضروری و تخصیص حافظه را کاهش می‌دهد. هنگامی که deleteApp روی یک نمونه FirebaseServerApp فراخوانی می‌شود، تعداد مرجع را کاهش می‌دهد و نمونه پس از رسیدن تعداد مرجع به صفر آزاد می‌شود.

پاکسازی نمونه‌های FirebaseServerApp

تشخیص زمان فراخوانی deleteApp روی یک نمونه FirebaseServerApp می‌تواند دشوار باشد، به خصوص اگر عملیات ناهمزمان زیادی را به صورت موازی اجرا می‌کنید. فیلد releaseOnDeref از FirebaseServerAppSettings به ساده‌سازی این امر کمک می‌کند. اگر به releaseOnDeref یک ارجاع به یک شیء با طول عمر دامنه درخواست (به عنوان مثال، شیء headers درخواست SSR) اختصاص دهید، FirebaseServerApp تعداد ارجاعات خود را هنگامی که چارچوب شیء header را پس می‌گیرد، کاهش می‌دهد. این کار به طور خودکار نمونه 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 با یک توکن Auth ID مقداردهی اولیه می‌شود، امکان پل زدن بین جلسات احراز هویت شده کاربر بین محیط‌های رندر سمت کلاینت (CSR) و رندر سمت سرور (SSR) را فراهم می‌کند. نمونه‌هایی از Firebase Auth SDK که با یک شیء FirebaseServerApp حاوی توکن Auth ID مقداردهی اولیه شده‌اند، بدون نیاز به اینکه برنامه هیچ روش ورود به سیستمی را فراخوانی کند، سعی می‌کنند کاربر را در هنگام مقداردهی اولیه وارد سیستم کنند.

ارائه یک توکن Auth ID به برنامه‌ها اجازه می‌دهد تا از هر یک از روش‌های ورود به سیستم 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 گنجانده می‌شود و به backend اجازه می‌دهد تا برنامه را اعتبارسنجی کند.

با این حال، از آنجا که 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.

توکن‌های کلاینت را به مرحله رندر سمت سرور منتقل کنید

برای انتقال توکن‌های احراز هویت‌شده‌ی Auth ID (و توکن‌های App Check) از کلاینت به مرحله‌ی رندرینگ سمت سرور (SSR)، از یک سرویس ورکر استفاده کنید. این رویکرد شامل رهگیری درخواست‌های واکشی (fetch) که SSR را فعال می‌کنند و افزودن توکن‌ها به هدرهای درخواست است.

برای پیاده‌سازی مرجع یک سرویس‌دهنده Firebase Auth به مدیریت جلسه با سرویس‌کارها مراجعه کنید. همچنین برای کدی که نحوه تجزیه این توکن‌ها از هدرها را برای استفاده در مقداردهی اولیه FirebaseServerApp نشان می‌دهد، به تغییرات سمت سرور مراجعه کنید.

استفاده از Firestore در محیط‌های SSR

هنگام ساخت برنامه‌های وب با رندرینگ سمت سرور (SSR)، اغلب برای بهینه‌سازی عملکرد و تجربه کاربری، نیاز به اشتراک‌گذاری داده‌ها بین سرور و کلاینت دارید. Firestore SDK ابزارهای سریال‌سازی را ارائه می‌دهد که به شما امکان می‌دهد اسنپ‌شات‌ها و انواع داده‌های خاص را روی سرور ضبط کرده و مستقیماً به اجزای سمت کلاینت خود منتقل کنید. این فرآیند با فعال کردن کلاینت برای هیدراته کردن حالت با استفاده از داده‌های از پیش واکشی شده در مرحله 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 را deserialize می‌کند:

import {
  Bytes
} from 'firebase/firestore';

// Assuming the same `bytesJSON` variable from the previous example.
const deserializedBytes = Bytes.fromJSON(bytesJSON);

سریالایز کردن و دی سریالایز کردن اسنپ‌شات‌های Firestore

مشابه انواع داده Firestore، می‌توانید نمونه‌های DocumentSnapshot و QuerySnapshot را با استفاده از toJSON سریالایز کنید. با این حال، برای deserialize کردن آنها، باید به جای یک متد استاتیک fromJSON از توابع مستقل documentSnapshotFromJSON و querySnapshotFromJSON استفاده کنید.

For example, the querySnapshot results of a query operation can be serialized using the toJSON method:

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();

سپس، این داده‌ها می‌توانند deserialize شوند:

import {
  querySnapshotFromJSON
} from 'firebase/firestore';

// deserializedSnapshot is an object of type QuerySnapshot:

const deserializedSnapshot =
  querySnapshotFromJSON(firestore, querySnapshotJson);

شنونده‌هایی با اسنپ‌شات‌های سریالی

اگرچه داده‌های پرس‌وجو شده در مرحله SSR برای رندر اولیه CSR شما ارزشمند هستند، اما ممکن است هنوز نیاز به نظارت بر سرویس Firestore برای به‌روزرسانی‌های بلادرنگ آن اطلاعات داشته باشید.

اگر برنامه شما به این به‌روزرسانی‌های بلادرنگ نیاز دارد، می‌توانید از تابع onSnapshotResume برای مقداردهی اولیه Firestore SnapshotListener ها با داده‌های سریالی 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);