SSR (Sunucu Tarafında Oluşturma) ile dinamik web uygulamalarında Firebase'i kullanma

Firebase JS SDK'sı veya diğer Firebase istemci SDK'larıyla çalıştıysanız FirebaseApp arayüzünü ve uygulama örneklerini yapılandırmak için bu arayüzün nasıl kullanılacağını biliyorsunuzdur. Firebase, sunucu tarafında benzer işlemlerin kolaylaştırılması için FirebaseServerApp sağlar.

FirebaseServerApp, sunucu tarafında oluşturma (SSR) ortamlarında kullanılmak üzere FirebaseApp öğesinin bir varyantıdır. İstemci taraflı oluşturma (CSR) ve sunucu taraflı oluşturma arasındaki ayrımı kapsayan Firebase oturumlarına devam etme araçları içerir. Bu araçlar ve stratejiler, Firebase ile oluşturulan ve Firebase App Hosting gibi Google ortamlarında dağıtılan dinamik web uygulamalarını geliştirmeye yardımcı olabilir.

FirebaseServerApp ile yapabilecekleriniz:

  • Tam yönetim haklarına sahip olan Firebase Admin SDK'nın aksine, user bağlamında sunucu tarafı kodu yürütün.
  • SSR ortamlarında Uygulama Kontrolü'nün kullanımını etkinleştirin.
  • İstemcide oluşturulan bir Firebase Auth oturumuna devam etme

FirebaseServerApp yaşam döngüsü

Sunucu tarafı oluşturma (SSR) çerçeveleri ve bulut çalışanları gibi tarayıcı dışı diğer çalışma zamanları, birden fazla yürütmede kaynakları yeniden kullanarak başlatma süresini optimize eder. FirebaseServerApp, referans sayısı mekanizması kullanarak bu ortamları destekleyecek şekilde tasarlanmıştır. Bir uygulama, önceki initializeServerApp ile aynı parametrelerle initializeServerApp çağırırsa zaten başlatılmış olan aynı FirebaseServerApp örneğini alır. Bu, gereksiz başlatma yükünü ve bellek ayırmalarını azaltır. deleteApp, FirebaseServerApp örneğinde çağrıldığında referans sayısı azalır ve referans sayısı sıfıra ulaştıktan sonra örnek serbest bırakılır.

FirebaseServerApp örneklerini temizleme

Özellikle birçok eşzamansız işlemi paralel olarak çalıştırıyorsanız FirebaseServerApp örneğinde deleteApp işlevini ne zaman çağırmanız gerektiğini bilmek zor olabilir. FirebaseServerAppSettings öğesinin releaseOnDeref alanı bu işlemi basitleştirir. İsteğin kapsamının yaşam süresine sahip bir nesneye (örneğin, SSR isteğinin başlıklar nesnesi) releaseOnDeref referansı atarsanız çerçeve başlık nesnesini geri aldığında FirebaseServerApp referans sayısını azaltır. Bu işlem, FirebaseServerApp örneğinizi otomatik olarak temizler.

releaseOnDeref kullanımına ilişkin bir örneği aşağıda bulabilirsiniz:

/// 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);
  ...
}

İstemcide oluşturulan kimliği doğrulanmış oturumlara devam etme

FirebaseServerApp örneği, kimlik doğrulama kimliği jetonuyla başlatıldığında kimliği doğrulanmış kullanıcı oturumlarının istemci tarafı oluşturma (CSR) ve sunucu tarafı oluşturma (SSR) ortamları arasında köprülenmesini sağlar. Bir kimlik doğrulama kimliği jetonu içeren FirebaseServerApp nesnesiyle başlatılan Firebase Auth SDK örnekleri, uygulamanın herhangi bir oturum açma yöntemi çağırmasına gerek kalmadan başlatma sırasında kullanıcının oturumunu açmaya çalışır.

Kimlik doğrulama kimliği jetonu sağlandığında uygulamalar, istemcide Kimlik Doğrulama'nın tüm oturum açma yöntemlerini kullanabilir. Bu sayede, kullanıcı etkileşimi gerektiren oturum açma yöntemleri için bile oturumun sunucu tarafında devam etmesi sağlanır. Ayrıca, kimliği doğrulanmış Firestore sorguları gibi yoğun işlemlerin sunucuya yüklenmesini sağlayarak uygulamanızın oluşturma performansını artırır.

/// 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.

SSR ortamlarında Uygulama Kontrolü'nü kullanma

Uygulama Kontrolü zorunluluğu, Firebase SDK'larının dahili olarak getToken işlevini çağırmak için kullandığı bir Uygulama Kontrolü SDK örneğine dayanır. Ardından, ortaya çıkan jeton tüm Firebase hizmetlerine yönelik isteklere dahil edilir ve arka ucun uygulamayı doğrulamasına olanak tanır.

Ancak Uygulama Kontrolü SDK'sının uygulama doğrulaması için belirli sezgisel yöntemlere erişmek üzere tarayıcıya ihtiyacı olduğundan sunucu ortamlarında başlatılamaz.

FirebaseServerApp alternatif bir çözüm sunar. FirebaseServerApp başlatma sırasında istemci tarafından oluşturulan bir Uygulama Kontrolü jetonu sağlanırsa Firebase hizmetleri çağrılırken Firebase ürün SDK'ları tarafından kullanılır. Bu sayede, Uygulama Kontrolü SDK örneğine gerek kalmaz.

/// 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.

İstemci jetonlarını sunucu taraflı oluşturma aşamasına iletme

Kimliği doğrulanmış Auth ID jetonlarını (ve Uygulama Kontrolü jetonlarını) istemciden sunucu tarafı oluşturma (SSR) aşamasına iletmek için bir hizmet çalışanı kullanın. Bu yaklaşımda, SSR'yi tetikleyen getirme istekleri yakalanır ve jetonlar istek başlıklarına eklenir.

Firebase Auth hizmet çalışanı için referans uygulama olarak Hizmet çalışanlarıyla oturum yönetimi başlıklı makaleyi inceleyin. Ayrıca, FirebaseServerApp başlatma işleminde kullanılmak üzere bu jetonların üst bilgilerden nasıl ayrıştırılacağını gösteren kod için Sunucu tarafındaki değişiklikler bölümüne bakın.

SSR ortamlarında Firestore'u kullanma

Sunucu tarafı oluşturma (SSR) ile web uygulamaları oluştururken performansı ve kullanıcı deneyimini optimize etmek için genellikle sunucu ile istemci arasında veri paylaşmanız gerekir. Firestore SDK, sunucuda anlık görüntüler ve belirli veri türlerini yakalamanıza ve bunları doğrudan istemci tarafı bileşenlerinize iletmenize olanak tanıyan serileştirme araçları sağlar. Bu işlem, istemcinin SSR aşamasında önceden getirilmiş verileri kullanarak durumu doldurmasını sağlayarak gereksiz getirme işlemlerini ortadan kaldırır. Ayrıca, bu serileştirilmiş durumlardan gerçek zamanlı dinleyicilere geçiş yaparak uygulamanızın veritabanıyla senkronize kalmasını sağlayabilirsiniz.

Bu bölümde, sunucu tarafında oluşturma (SSR) aşamasında alınan verilerin istemci tarafı bileşenlerinde nasıl yeniden kullanılacağı açıklanmaktadır.

Veri Türlerini Serileştirme

Belirli Firestore veri türleri, verilerini serileştirilebilir bir biçime dönüştürmek için toJSON yöntemi sağlar. Bunlar arasında Bytes, GeoPoint, Timestamp ve VectorValue gibi nesnelerin örnekleri yer alır.

Veriler JSON biçiminde olduğunda, bunları standart çerçeve mekanizmaları aracılığıyla sunucudan istemciye veya ayrımı kapsayan bileşenlere parametre olarak iletebilirsiniz. Örneğin:

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

Veri Türlerini Seri Halinden Çıkarma

Firestore veri türleri, serileştirilmiş verileri kullanılabilir bir Firestore veri türüne dönüştürmek için fromJSON statik yöntemini içerir.

Örneğin, aşağıdakiler bir Bytes veri türünü seri durumdan çıkarır:

import {
  Bytes
} from 'firebase/firestore';

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

Firestore anlık görüntülerini serileştirme ve seri durumdan çıkarma

Firestore veri türlerine benzer şekilde, DocumentSnapshot ve QuerySnapshot örneklerini toJSON kullanarak serileştirebilirsiniz. Ancak bunları seri durumdan çıkarmak için statik bir fromJSON yöntemi yerine bağımsız işlevler documentSnapshotFromJSON ve querySnapshotFromJSON kullanmanız gerekir.

Örneğin, querySnapshot işleminin query sonuçları, toJSON yöntemi kullanılarak serileştirilebilir:

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

Ardından bu veriler seri durumdan çıkarılabilir:

import {
  querySnapshotFromJSON
} from 'firebase/firestore';

// deserializedSnapshot is an object of type QuerySnapshot:

const deserializedSnapshot =
  querySnapshotFromJSON(firestore, querySnapshotJson);

Serileştirilmiş anlık görüntülerle dinleyiciler

SSR aşamasında sorgulanan veriler ilk CSR oluşturma işlemi için değerli olsa da bu bilgilerdeki gerçek zamanlı güncellemeler için Firestore hizmetini izlemeniz gerekebilir.

Uygulamanız bu anlık güncellemeleri gerektiriyorsa Firestore'u serileştirilmiş Snapshot verilerle başlatmak için onSnapshotResume işlevini kullanabilirsiniz.SnapshotListener Örneğin:

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