Atualizar da API com namespace para a API modular

Os aplicativos que atualmente usam qualquer Firebase Web API com namespace, desde as bibliotecas compat até a versão 8 ou anterior, devem considerar a migração para a API modular usando as instruções deste guia.

Este guia pressupõe que você esteja familiarizado com a API com namespace e que aproveitará as vantagens de um empacotador de módulo, como webpack ou Rollup , para atualização e desenvolvimento contínuo de aplicativos modulares.

É altamente recomendável usar um empacotador de módulo em seu ambiente de desenvolvimento. Se você não usar um, não poderá aproveitar os principais benefícios da API modular no tamanho reduzido do aplicativo. Você precisará do npm ou do fio para instalar o SDK.

As etapas de atualização neste guia serão baseadas em um aplicativo Web imaginário que usa os SDKs Authentication e Cloud Firestore. Ao trabalhar com os exemplos, você poderá dominar os conceitos e as etapas práticas necessárias para atualizar todos os SDKs da Web do Firebase compatíveis.

Sobre as bibliotecas com namespace ( compat )

Existem dois tipos de bibliotecas disponíveis para o Firebase Web SDK:

  • Modular - uma nova superfície de API projetada para facilitar o tree-shaking (remoção de código não utilizado) para tornar seu aplicativo da web o mais pequeno e rápido possível.
  • Namespaced ( compat ) – uma superfície de API familiar que é totalmente compatível com as versões anteriores do SDK, permitindo que você atualize sem alterar todo o código do Firebase de uma só vez. As bibliotecas compatíveis têm pouca ou nenhuma vantagem de tamanho ou desempenho em relação às suas contrapartes com namespace.

Este guia pressupõe que você aproveitará as vantagens das bibliotecas de compatibilidade para facilitar sua atualização. Essas bibliotecas permitem que você continue usando código com namespace juntamente com código refatorado para a API modular. Isso significa que você pode compilar e depurar seu aplicativo com mais facilidade à medida que avança no processo de atualização.

Para aplicativos com uma exposição muito pequena ao Firebase Web SDK (por exemplo, um aplicativo que faz apenas uma chamada simples para as APIs de autenticação), pode ser prático refatorar códigos com namespaces mais antigos sem usar as bibliotecas de compatibilidade. Se você estiver atualizando um aplicativo desse tipo, poderá seguir as instruções neste guia para "a API modular" sem usar as bibliotecas de compatibilidade.

Sobre o processo de atualização

Cada etapa do processo de atualização tem um escopo definido para que você possa terminar de editar a fonte do seu aplicativo e, em seguida, compilá-lo e executá-lo sem interrupções. Em resumo, aqui está o que você fará para atualizar um aplicativo:

  1. Adicione as bibliotecas modulares e as bibliotecas de compatibilidade ao seu aplicativo.
  2. Atualize as instruções de importação no seu código para compatibilidade.
  3. Refatore o código de um único produto (por exemplo, Autenticação) para o estilo modular.
  4. Opcional: neste ponto, remova a biblioteca de compatibilidade de autenticação e o código de compatibilidade para autenticação para obter o benefício do tamanho do aplicativo para autenticação antes de continuar.
  5. Refatore funções para cada produto (por exemplo, Cloud Firestore, FCM, etc.) para o estilo modular, compilando e testando até que todas as áreas estejam concluídas.
  6. Atualize o código de inicialização para o estilo modular.
  7. Remova todas as instruções e códigos de compatibilidade restantes do seu aplicativo.

Obtenha a versão mais recente do SDK

Para começar, obtenha as bibliotecas modulares e bibliotecas de compatibilidade usando npm:

npm i firebase@10.9.0

# OR

yarn add firebase@10.9.0

Atualizar importações para compatibilidade

Para manter seu código funcionando após atualizar suas dependências, altere suas instruções de importação para usar a versão "compatível" de cada importação. Por exemplo:

Antes: versão 8 ou anterior

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

Depois: compatibilidade

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

Refatore para o estilo modular

Embora as APIs com namespace sejam baseadas em um namespace e um padrão de serviço encadeados por pontos, a abordagem modular significa que seu código será organizado principalmente em torno de funções . Na API modular, o pacote firebase/app e outros pacotes não retornam uma exportação abrangente que contenha todos os métodos do pacote. Em vez disso, os pacotes exportam funções individuais.

Na API modular, os serviços são passados ​​como primeiro argumento e a função usa os detalhes do serviço para fazer o resto. Vamos examinar como isso funciona em dois exemplos que refatoram chamadas para as APIs Authentication e Cloud Firestore.

Exemplo 1: refatorando uma função de autenticação

Antes: compatibilidade

O código de compatibilidade é idêntico ao código com namespace, mas as importações foram alteradas.

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

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

Depois: modular

A função getAuth usa firebaseApp como primeiro parâmetro. A função onAuthStateChanged não é encadeada da instância auth como seria na API com namespace; em vez disso, é uma função gratuita que usa auth como primeiro parâmetro.

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

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

Tratamento de atualização do método Auth getRedirectResult

A API modular introduz uma alteração significativa em getRedirectResult . Quando nenhuma operação de redirecionamento é chamada, a API modular retorna null em oposição à API com namespace, que retornou um UserCredential com um usuário null .

Antes: compatibilidade

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

Depois: modular

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;

Exemplo 2: refatoração de uma função do Cloud Firestore

Antes: compatibilidade

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

Depois: modular

A função getFirestore usa firebaseApp como seu primeiro parâmetro, que foi retornado de initializeApp em um exemplo anterior. Observe como o código para formar uma consulta é muito diferente na API modular; não há encadeamento e métodos como query ou where agora são expostos como funções livres.

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

Atualizar referências ao Firestore DocumentSnapshot.exists

A API modular introduz uma alteração significativa na qual a propriedade firestore.DocumentSnapshot.exists foi alterada para um método . A funcionalidade é essencialmente a mesma (testar se existe um documento), mas você deve refatorar seu código para usar o método mais recente, conforme mostrado:

Antes:compatível

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

Depois: modular

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

Exemplo 3: combinando estilos de código modular e com namespace

O uso das bibliotecas de compatibilidade durante a atualização permite que você continue usando o código com namespace juntamente com o código refatorado para a API modular. Isso significa que você pode manter o código com namespace existente para o Cloud Firestore enquanto refatora o Authentication ou outro código do SDK do Firebase para o estilo modular e ainda assim compila seu aplicativo com êxito com ambos os estilos de código. O mesmo se aplica ao código de API modular e com namespace em um produto como o Cloud Firestore; estilos de código novos e antigos podem coexistir, desde que você esteja importando os pacotes de compatibilidade:

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

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

Lembre-se de que, embora seu aplicativo seja compilado, você não obterá os benefícios de tamanho do aplicativo do código modular até remover totalmente as instruções e o código de compatibilidade do seu aplicativo.

Atualizar código de inicialização

Atualize o código de inicialização do seu app para usar a sintaxe modular. É importante atualizar esse código depois de concluir a refatoração de todo o código em seu aplicativo; isso ocorre porque firebase.initializeApp() inicializa o estado global para as APIs compatíveis e modulares, enquanto a função modular initializeApp() inicializa apenas o estado para modular.

Antes: compatibilidade

import firebase from "firebase/compat/app"

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

Depois: modular

import { initializeApp } from "firebase/app"

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

Remover código de compatibilidade

Para aproveitar os benefícios de tamanho da API modular, você deve eventualmente converter todas as invocações para o estilo modular mostrado acima e remover todas as instruções import "firebase/compat/* do seu código. Quando terminar, não deverá haver mais referências ao namespace global firebase.* ou qualquer outro código no estilo API com namespace.

Usando a biblioteca de compatibilidade da janela

A API modular é otimizada para funcionar com módulos em vez do objeto window do navegador. Versões anteriores da biblioteca permitiam o carregamento e gerenciamento do Firebase usando o namespace window.firebase . Isso não é recomendado no futuro, pois não permite a eliminação de código não utilizado. No entanto, a versão compatível do JavaScript SDK funciona com a window para desenvolvedores que preferem não iniciar imediatamente o caminho de atualização modular.

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

A biblioteca de compatibilidade usa código modular subjacente e fornece a mesma API da API com namespace; isso significa que você pode consultar a referência da API com namespace e os trechos de código com namespace para obter detalhes. Este método não é recomendado para uso a longo prazo, mas como um começo para atualizar para a biblioteca totalmente modular.

Benefícios e limitações do SDK modular

O SDK totalmente modularizado tem estas vantagens em relação às versões anteriores:

  • O SDK modular permite um tamanho de aplicativo drasticamente reduzido. Ele adota o formato moderno do Módulo JavaScript, permitindo práticas de "tremor de árvore" nas quais você importa apenas os artefatos que seu aplicativo precisa. Dependendo do seu aplicativo, a agitação da árvore com o SDK modular pode resultar em 80% menos quilobytes do que um aplicativo comparável criado usando a API com namespace.
  • O SDK modular continuará a se beneficiar do desenvolvimento contínuo de recursos, enquanto a API com namespace não.