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ı biliyor olabilirsiniz. Firebase, sunucu tarafında benzer işlemlerin kolaylaştırılması için FirebaseServerApp sağlar.

FirebaseServerApp, sunucu tarafı oluşturma (SSR) ortamlarında kullanılmak üzere FirebaseApp öğesinin bir varyantıdır. İstemci taraflı oluşturma (CSR) ve sunucu tarafı 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 edin.

FirebaseServerApp yaşam döngüsü

Sunucu tarafı oluşturma (SSR) çerçeveleri ve bulut çalışanları gibi diğer tarayıcı dışı çalışma zamanları, birden fazla yürütme arasında 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, bir 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 bir 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. releaseOnDeref öğesini, isteğin kapsamının yaşam süresine sahip bir nesneye (ör. SSR isteğinin başlıklar nesnesi) referans olarak atarsanız releaseOnDeref, çerçeve başlık nesnesini geri aldığında referans sayısını azaltır.FirebaseServerApp Bu işlem, FirebaseServerApp örneğinizi otomatik olarak temizler.

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

/// 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ış oturumları devam ettirme

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

Kimlik doğrulama kimliği jetonu sağlandığında uygulamalar, istemcideki tüm kimlik doğrulama oturumu 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 App Check'i kullanma

Uygulama Kontrolü'nün zorunlu kılınması, Firebase SDK'larının getToken işlevini dahili olarak ç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 App Check SDK'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 App Check 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ı değişiklikleri 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 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 fromJSON yöntemi yerine bağımsız documentSnapshotFromJSON ve querySnapshotFromJSON işlevlerini kullanmanız gerekir.

Örneğin, query işleminin querySnapshot 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ın bu anlık güncellemeleri gerektirmesi durumunda, Firestore'u onSnapshotResume işleviyle başlatarak SnapshotListener, Snapshot verilerini seri hale getirebilirsiniz. Ö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);