Przejście z interfejsu API z nazwą przestrzeni nazw na interfejs API w wersji modułowej

Aplikacje, które obecnie korzystają z dowolnego interfejsu Firebase Web API w dowolnej przestrzeni nazw (z bibliotek compat w wersji 8 lub starszej), powinny rozważyć migrację do interfejsu modularnego API zgodnie z instrukcjami podanymi w tym przewodniku.

W tym przewodniku zakładamy, że znasz interfejs API z nazwą przestrzeni nazw i że do uaktualniania oraz dalszego tworzenia modułowej aplikacji będziesz używać usługi tworzenia pakietów modułów, takiej jak webpack lub Rollup.

Zdecydowanie zalecamy korzystanie z pakowacza modułów w środowisku programistycznym. Jeśli nie użyjesz żadnego z nich, nie będziesz mieć możliwości skorzystania z głównych zalet interfejsu API w zakresie zmniejszenia rozmiaru aplikacji. Aby zainstalować pakiet SDK, musisz użyć npm lub yarn.

Kroki uaktualniania w tym przewodniku będą oparte na przykładowej aplikacji internetowej, która korzysta z pakietów SDK AuthenticationCloud Firestore. Dzięki przykładom możesz poznać zagadnienia i konkretne kroki wymagane do uaktualnienia wszystkich obsługiwanych pakietów SDK Firebase Web.

Informacje o bibliotekach w przestrzeni nazw (compat)

W przypadku pakietu Firebase Web SDK dostępne są 2 typy bibliotek:

  • Modularność – nowa wersja interfejsu API, która ułatwia usuwanie zbędącego kodu (czyli jego usuwanie z drzewa), aby Twoja aplikacja internetowa była jak najmniejsza i jak najszybsza.
  • W przestrzeni nazw (compat) – znajoma interfejs API, który jest w pełni zgodny z wcześniejszymi wersjami pakietu SDK. Umożliwia to uaktualnienie bez jednoczesnej zmiany całego kodu Firebase. Biblioteki zgodności mają niewielką przewagę nad bibliotekami z przestrzenią nazw pod względem rozmiaru i wydajności.

W tym przewodniku zakładamy, że użyjesz bibliotek kompatybilnych, aby ułatwić sobie przekształcenie. Te biblioteki umożliwiają dalsze używanie kodu z przestrzenią nazw obok kodu zmodyfikowanego pod kątem interfejsu API w wersji modułowej. Oznacza to, że podczas procesu aktualizacji możesz łatwiej skompilować i przeprowadzić debugowanie aplikacji.

W przypadku aplikacji, które korzystają z pakietu SDK Firebase Web w niewielkim stopniu (np. aplikacji, która wykonuje tylko proste wywołanie interfejsów API Authentication), warto zrefaktoryzować starszy kod z nazwą przestrzeni bez używania bibliotek zgodnych z wersją. Jeśli aktualizujesz taką aplikację, możesz postępować zgodnie z instrukcjami w tym przewodniku dotyczącymi „Modułowego interfejsu API” bez używania bibliotek zgodności.

Proces uaktualniania

Każdy krok procesu uaktualniania jest ograniczony, aby umożliwić Ci dokończenie edycji kodu źródłowego aplikacji, a następnie jej skompilowanie i uruchomienie bez żadnych problemów. Oto, co musisz zrobić, aby zaktualizować aplikację:

  1. Dodaj do aplikacji modułowe biblioteki i biblioteki zgodności.
  2. Zaktualizuj instrukcje importowania w kodzie, aby używały pakietu compat.
  3. Przerzuć kod pojedynczego produktu (np. Authentication) do stylu modułowego.
  4. Opcjonalnie: na tym etapie usuń bibliotekę zgodności Authentication i kod zgodności dla Authentication, aby uzyskać korzyści związane z rozmiarem aplikacji dla Authentication, zanim przejdziesz dalej.
  5. Przepisz funkcje każdego produktu (np. Cloud Firestore, FCM itp.) w stylu modułowym, kompilując i testując, aż wszystkie obszary zostaną ukończone.
  6. Zaktualizuj kod inicjowania do stylu modułowego.
  7. Usuń ze swojej aplikacji wszystkie pozostałe oświadczenia i kod zgodności.

Pobieranie najnowszej wersji pakietu SDK

Aby rozpocząć, pobierz biblioteki modułowe i biblioteki zgodne za pomocą npm:

npm i firebase@11.1.0

# OR

yarn add firebase@11.1.0

Aktualizowanie importów do wersji zgodnej

Aby kod działał prawidłowo po zaktualizowaniu zależności, zmień instrukcje importu, aby używać wersji „compat” każdego importu. Przykład:

Wcześniej: wersja 8 lub starsza

import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';

Po: compat

// compat packages are API compatible with namespaced code
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';

Przerzuć się na styl modułowy

Chociaż interfejsy API z przestrzenią nazw są oparte na wzorze przestrzeni nazw i usług połączonych kropką, podejście modułowe oznacza, że Twój kod będzie zorganizowany głównie wokół funkcji. W modularnym interfejsie API pakiet firebase/app i inne pakiety nie zwracają kompleksowego eksportu zawierającego wszystkie metody z pakietu. Zamiast tego pakiety eksportują poszczególne funkcje.

W interfejsie API w wersji modułowej usługi są przekazywane jako pierwszy argument, a funkcja wykorzystuje szczegóły usługi do wykonania reszty czynności. Przyjrzyjmy się, jak to działa na przykładzie dwóch przykładów, które refaktoryzują wywołania interfejsów API AuthenticationCloud Firestore.

Przykład 1. Refaktoryzacja funkcji Authentication

Wcześniej: zgodność

Kod zgodności jest identyczny z kodem w przestrzeni nazw, ale importy zostały zmienione.

import firebase from "firebase/compat/app";
import "firebase/compat/auth";

const auth = firebase.auth();
auth.onAuthStateChanged(user => { 
  // Check for user status
});

Po: modułowe

Funkcja getAuth przyjmuje jako pierwszy parametr firebaseApp. Funkcja onAuthStateChanged nie jest powiązana z instancją auth, jak ma to miejsce w przypadku interfejsu API z nazwą przestrzeni nazw. Zamiast tego jest to wolna funkcja, która jako pierwszy parametr przyjmuje wartość auth.

import { getAuth, onAuthStateChanged } from "firebase/auth";

const auth = getAuth(firebaseApp);
onAuthStateChanged(auth, user => {
  // Check for user status
});

Aktualizacja obsługi metody uwierzytelniania getRedirectResult

Interfejs API w wersji modułowej wprowadza zmiany w interfejsie getRedirectResult. Gdy nie wywołano żadnej operacji przekierowania, interfejs modularny zwraca null, a nie interfejs z przestrzenią nazw, który zwraca UserCredential z użytkownikiem null.

Wcześniej: zgodność

const result = await auth.getRedirectResult()
if (result.user === null && result.credential === null) {
  return null;
}
return result;

Po: modułowe

const result = await getRedirectResult(auth);
// Provider of the access token could be Facebook, Github, etc.
if (result === null || provider.credentialFromResult(result) === null) {
  return null;
}
return result;

Przykład 2. Refaktoryzacja funkcji Cloud Firestore

Wcześniej: zgodność

import "firebase/compat/firestore"

const db = firebase.firestore();
db.collection("cities").where("capital", "==", true)
    .get()
    .then((querySnapshot) => {
        querySnapshot.forEach((doc) => {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch((error) => {
        console.log("Error getting documents: ", error);
    });

Po: modułowe

Funkcja getFirestore przyjmuje jako pierwszy parametr firebaseApp, który został zwrócony przez funkcję initializeApp w poprzednim przykładzie. Zwróć uwagę, że kod służący do tworzenia zapytania jest w modularnym interfejsie API bardzo różny. Nie ma w nim łańcuchów, a metody takie jak query czy where są teraz dostępne jako funkcje wolne.

import { getFirestore, collection, query, where, getDocs } from "firebase/firestore";

const db = getFirestore(firebaseApp);

const q = query(collection(db, "cities"), where("capital", "==", true));

const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
  // doc.data() is never undefined for query doc snapshots
  console.log(doc.id, " => ", doc.data());
});

Aktualizowanie odwołań do Firestore DocumentSnapshot.exists

Modułowe API wprowadza istotną zmianę, w której właściwość firestore.DocumentSnapshot.exists została zastąpiona przez metodę. Funkcjonalność jest zasadniczo taka sama (sprawdzanie, czy dokument istnieje), ale musisz przerobić kod, aby używać nowszej metody:

Przed:compat

if (snapshot.exists) {
  console.log("the document exists");
}

Po: modułowe

if (snapshot.exists()) {
  console.log("the document exists");
}

Przykład 3. Łączenie stylów kodu z przestrzenią nazw i modułowym kodem

Korzystanie z bibliotek zgodnych podczas uaktualniania umożliwia dalsze używanie kodu z przestrzenią nazw obok kodu zrefaktoryzowanego pod kątem modułowego interfejsu API. Oznacza to, że możesz zachować istniejący kod w przestrzeni nazw dla pakietu Cloud Firestore, a zarazem przeprowadzić refaktoryzację kodu Authentication lub innego kodu pakietu SDK Firebase do stylu modułowego. Nadal możesz kompilować aplikację z użyciem obu tych stylów. To samo dotyczy kodu interfejsu API z przestrzenią nazw i interfejsu API w formie modułów w ramach usługi, takiej jak Cloud Firestore. Nowe i stare style kodu mogą współistnieć, o ile importujesz pakiety zgodne:

import firebase from 'firebase/compat/app';
import 'firebase/compat/firestore';
import { getDoc } from 'firebase/firestore'

const docRef = firebase.firestore().doc();
getDoc(docRef);

Pamiętaj, że chociaż kompilacja aplikacji się powiedzie, nie uzyskasz korzyści wynikających z mniejszego rozmiaru kodu modułowego, dopóki nie usuniesz z aplikacji instrukcji kompatybilności i kodu.

Aktualizowanie kodu inicjowania

Zaktualizuj kod inicjalizacji aplikacji, aby używać składni modułowej. Należy zaktualizować ten kod po zakończeniu refaktoryzacji całego kodu w aplikacji. Dzieje się tak, ponieważ funkcja firebase.initializeApp() inicjuje stan globalny zarówno dla interfejsów API kompatybilnych, jak i modularnych, a funkcja modularna initializeApp() inicjuje tylko stan dla interfejsu modularnego.

Wcześniej: zgodność

import firebase from "firebase/compat/app"

firebase.initializeApp({ /* config */ });

Po: modułowe

import { initializeApp } from "firebase/app"

const firebaseApp = initializeApp({ /* config */ });

Usuwanie kodu zgodności

Aby uzyskać korzyści wynikające z interfejsu API w wersji modułowej, musisz przekształcić wszystkie wywołania w modułowy styl pokazany powyżej i usunąć z kodu wszystkie instrukcje import "firebase/compat/*. Po zakończeniu nie powinno być już żadnych odwołań do globalnej przestrzeni nazw firebase.* ani innych fragmentów kodu w stylu interfejsu API z przestrzenią nazw.

Korzystanie z biblioteki kompatybilności w oknie

Interfejs modularny API jest zoptymalizowany pod kątem pracy z modułami, a nie obiektem window przeglądarki. W poprzednich wersjach biblioteki można było wczytywać i zarządzać Firebase za pomocą przestrzeni nazw window.firebase. Nie zalecamy tego w przyszłości, ponieważ nie pozwala na wyeliminowanie nieużywanego kodu. Wersja zgodna pakietu SDK JavaScript działa jednak z window w przypadku deweloperów, którzy nie chcą od razu przechodzić na modułową ścieżkę aktualizacji.

<script src="https://www.gstatic.com/firebasejs/11.1.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.1.0/firebase-firestore-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.1.0/firebase-auth-compat.js"></script>
<script>
   const firebaseApp = firebase.initializeApp({ /* Firebase config */ });
   const db = firebaseApp.firestore();
   const auth = firebaseApp.auth();
</script>

Biblioteka zgodności używa modułowego kodu i zapewnia ten sam interfejs API co interfejs z przestrzenią nazw. Oznacza to, że szczegółowe informacje znajdziesz w dokumentacji interfejsu API z przestrzenią nazw i fragmentach kodu z przestrzenią nazw. Ta metoda nie jest zalecana do długotrwałego stosowania, ale może być użyta jako pierwszy krok w przechodzeniu na całkowicie modułową bibliotekę.

Zalety i ograniczenia modułowego pakietu SDK

W pełni modułowy pakiet SDK ma te zalety w porównaniu z wcześniejszymi wersjami:

  • Modułowy pakiet SDK pozwala znacznie zmniejszyć rozmiar aplikacji. Jest ono oparte na nowoczesnym formacie modułu JavaScript, który umożliwia „tree shaking” (czyli usuwanie z drzewa) i importowanie tylko tych artefaktów, których potrzebuje aplikacja. W zależności od aplikacji, zastosowanie metody tree-shaking w ramach modułowego pakietu SDK może spowodować zmniejszenie rozmiaru aplikacji o 80% w porównaniu z porównywalną aplikacją utworzoną przy użyciu interfejsu API z nazwą przestrzeni nazw.
  • Modułowy pakiet SDK będzie nadal korzystać z rozwijanych funkcji, podczas gdy interfejs API z przestrzenią nazw nie będzie.