Обновление API с пространством имен до модульного приложения.

Приложениям, использующим любой веб-API Firebase с пространством имен, начиная с библиотек compat и заканчивая версией 8 или более ранней, следует рассмотреть возможность перехода на модульный API, используя инструкции в этом руководстве.

В этом руководстве предполагается, что вы знакомы с API с использованием пространств имен и будете использовать сборщики модулей, такие как webpack или Rollup, для обновления и дальнейшей модульной разработки приложений.

Настоятельно рекомендуется использовать сборщик модулей в вашей среде разработки. Без него вы не сможете воспользоваться основными преимуществами модульного API, такими как уменьшение размера приложения. Для установки SDK вам потребуется npm или yarn .

В этом руководстве описаны шаги обновления на примере вымышленного веб-приложения, использующего SDK Authentication и Cloud Firestore . Проработав примеры, вы сможете освоить концепции и практические шаги, необходимые для обновления всех поддерживаемых веб-SDK Firebase.

О библиотеках с пространством имен ( compat библиотеках)

Для веб-SDK Firebase доступны два типа библиотек:

  • Modular — это новый интерфейс API, разработанный для упрощения процесса оптимизации кода (удаления неиспользуемого кода), чтобы сделать ваше веб-приложение максимально компактным и быстрым.
  • Совместимость с пространствами имен ( compat ) — это привычный интерфейс API, полностью совместимый с более ранними версиями SDK, позволяющий обновлять систему без одновременного изменения всего кода Firebase. Библиотеки Compat практически не имеют преимуществ в размере или производительности по сравнению со своими аналогами с пространствами имен.

В этом руководстве предполагается, что вы воспользуетесь библиотеками совместимости для упрощения процесса обновления. Эти библиотеки позволяют продолжать использовать код с пространствами имен наряду с кодом, рефакторизованным для модульного API. Это означает, что вы сможете проще компилировать и отлаживать свое приложение в процессе обновления.

Для приложений с очень небольшим использованием веб-SDK Firebase — например, для приложений, которые выполняют лишь простые вызовы к API Authentication — может быть целесообразно рефакторизовать старый код с пространствами имен без использования библиотек совместимости. Если вы обновляете такое приложение, вы можете следовать инструкциям в этом руководстве по «модульному API» без использования библиотек совместимости.

О процессе обновления

Каждый этап процесса обновления спланирован таким образом, чтобы вы могли завершить редактирование исходного кода вашего приложения, а затем скомпилировать и запустить его без сбоев. Вкратце, вот что вам нужно сделать, чтобы обновить приложение:

  1. Добавьте модульные библиотеки и библиотеки совместимости в ваше приложение.
  2. Обновите операторы импорта в вашем коде для обеспечения совместимости.
  3. Переработайте код для отдельного продукта (например, Authentication ), приведя его в модульный стиль.
  4. Необязательно: на этом этапе удалите библиотеку совместимости Authentication и код совместимости для Authentication , чтобы получить выгоду от увеличения размера приложения благодаря Authentication , прежде чем продолжить.
  5. Функционал каждого продукта (например, Cloud Firestore , FCM и т. д.) следует переработать в модульном стиле, компилируя и тестируя его до тех пор, пока все области не будут завершены.
  6. Обновите код инициализации в соответствии с модульным стилем.
  7. Удалите все оставшиеся операторы совместимости и код совместимости из вашего приложения.

Получите последнюю версию SDK.

Для начала загрузите модульные и совместимые библиотеки с помощью npm:

npm i firebase@12.7.0

# OR

yarn add firebase@12.7.0

Обновите импорт для обеспечения совместимости.

Чтобы ваш код продолжал работать после обновления зависимостей, измените операторы импорта, используя "совместимую" версию каждого импорта. Например:

До: версия 8 или более ранняя

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

После: совместимость

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

Переведите код на модульный стиль.

В то время как API с пространствами имен основаны на шаблоне цепочек имен и сервисов, модульный подход означает, что ваш код будет организован в основном вокруг функций . В модульном API пакет firebase/app и другие пакеты не возвращают исчерпывающий экспорт, содержащий все методы пакета. Вместо этого пакеты экспортируют отдельные функции.

В модульном API сервисы передаются в качестве первого аргумента, а затем функция использует данные сервиса для выполнения остальных действий. Давайте рассмотрим, как это работает на двух примерах, которые переписывают вызовы к API Authentication и Cloud Firestore .

Пример 1: рефакторинг функции Authentication

Ранее: совместимость

Совместимый код идентичен коду с пространством имен, но импорты изменились.

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

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

После: модульный

Функция getAuth принимает firebaseApp в качестве первого параметра. Функция onAuthStateChanged не связана с экземпляром auth , как это было бы в API с пространством имен; вместо этого это свободная функция, которая принимает auth в качестве первого параметра.

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

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

Обновить обработку метода аутентификации getRedirectResult

Модульный API вносит существенные изменения в getRedirectResult . Если операция перенаправления не вызывается, модульный API возвращает null в отличие от API с пространством имен, который возвращал UserCredential с null пользователем.

Ранее: совместимость

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

После: модульный

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;

Пример 2: рефакторинг функции Cloud Firestore

Ранее: совместимость

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

После: модульный

Функция getFirestore принимает firebaseApp в качестве первого параметра, который в предыдущем примере был возвращен функцией initializeApp . Обратите внимание, что код для формирования запроса в модульном API сильно отличается; здесь нет цепочек вызовов, а такие методы, как query или where , теперь доступны как свободные функции.

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

Обновите ссылки на Firestore DocumentSnapshot.exists

В модульном API внесено критическое изменение: свойство firestore.DocumentSnapshot.exists было заменено методом . Функциональность, по сути, осталась прежней (проверка существования документа), но для использования нового метода необходимо переписать код, как показано ниже:

До: совместимость

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

После: модульный

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

Пример 3: сочетание стилей кода с использованием пространств имен и модульного подхода.

Использование совместимых библиотек во время обновления позволяет продолжать использовать код с пространствами имен наряду с кодом, переработанным для модульного API. Это означает, что вы можете сохранить существующий код с пространствами имен для Cloud Firestore , пока перерабатываете код Authentication или другой код Firebase SDK в модульном стиле, и при этом успешно компилировать ваше приложение с обоими стилями кода. То же самое справедливо для кода API с пространствами имен и модульного API в таком продукте, как Cloud Firestore ; новые и старые стили кода могут сосуществовать, если вы импортируете совместимые пакеты:

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

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

Имейте в виду, что, хотя ваше приложение и скомпилируется, вы не получите преимуществ модульного кода в плане уменьшения его размера, пока полностью не удалите из приложения операторы совместимости и соответствующий код.

Обновить код инициализации

Обновите код инициализации вашего приложения, чтобы использовать модульный синтаксис. Важно обновить этот код после завершения рефакторинга всего кода в вашем приложении, поскольку firebase.initializeApp() инициализирует глобальное состояние как для совместимого, так и для модульного API, тогда как модульная функция initializeApp() инициализирует состояние только для модульного API.

Ранее: совместимость

import firebase from "firebase/compat/app"

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

После: модульный

import { initializeApp } from "firebase/app"

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

Удалить код совместимости

Чтобы в полной мере оценить преимущества модульного API с точки зрения экономии места, в конечном итоге следует преобразовать все вызовы в модульный стиль, показанный выше, и удалить все операторы import "firebase/compat/* из вашего кода. После этого в коде не должно быть ссылок на глобальное пространство имен firebase.* или любой другой код в стиле API с пространствами имен.

Используя библиотеку совместимости из окна

Модульный API оптимизирован для работы с модулями, а не с объектом window браузера. В предыдущих версиях библиотеки загрузка и управление Firebase осуществлялись с помощью пространства имен window.firebase . В дальнейшем это не рекомендуется, поскольку не позволяет удалять неиспользуемый код. Однако совместимая версия JavaScript SDK работает с window для разработчиков, которые предпочитают не начинать сразу же модульный процесс обновления.

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

Библиотека совместимости использует модульный код и предоставляет тот же API, что и API с пространствами имен; это означает, что вы можете обратиться к справочнику по API с пространствами имен и фрагментам кода с пространствами имен для получения подробной информации. Этот метод не рекомендуется для длительного использования, но может служить отправной точкой для перехода на полностью модульную библиотеку.

Преимущества и ограничения модульного SDK

Полностью модульный SDK обладает следующими преимуществами по сравнению с более ранними версиями:

  • Модульный SDK позволяет значительно уменьшить размер приложения. Он использует современный формат модулей JavaScript, что позволяет применять метод «удаления ненужных файлов» (tree shaking), при котором импортируются только необходимые вашему приложению компоненты. В зависимости от вашего приложения, удаление ненужных файлов с помощью модульного SDK может привести к уменьшению размера приложения на 80% по сравнению с аналогичным приложением, созданным с использованием API с пространствами имен.
  • Модульный SDK продолжит получать выгоду от постоянного развития функционала, в то время как API с пространствами имен этого не сделает.