バージョン 8 からモジュラー Web SDK へのアップグレード

アプリが Firebase Web SDK バージョン 8 以前を使用している場合は、このガイドの手順に沿ってバージョン 9 に移行することをおすすめします。

このガイドは、読者がバージョン 8 に精通していること、webpackRollup などのモジュール バンドラを利用してバージョン 9 へのアップグレードと継続的な開発を行うことを前提としています。

開発環境でモジュール バンドラを使用することを強くおすすめします。モジュール バンドラを使用しない場合、バージョン 9 の主要なメリットであるアプリのサイズ削減を実現できません。SDK をインストールするには、npm または yarn が必要です。

このガイドのアップグレード手順は、Authentication SDK と Cloud Firestore SDK を使用する架空のウェブアプリをベースにしています。サンプルに取り組むことで、サポートされているすべての Firebase Web SDK のアップグレードに必要なコンセプトと実用的な手順を習得できます。

互換ライブラリについて

Firebase Web SDK バージョン 9 で使用できるライブラリには 2 つのタイプがあります。

  • モジュラー - ウェブアプリをできる限り小さくして高速化するためのツリー シェイキング(未使用のコードの削除)を可能にする新しい API サーフェス。
  • 互換 - バージョン 8 SDK と完全な互換性を持つ、使い慣れた API サーフェス。すべての Firebase コードを一度に変更することなく、バージョン 9 にアップグレードできます。バージョン 8 と比較して、互換ライブラリにはサイズやパフォーマンス上のメリットはほとんどありません。

このガイドでは、アップグレードを容易にするためにバージョン 9 互換ライブラリを利用することを前提としています。これらのライブラリでは、バージョン 9 用にリファクタリングされたコードとともに、バージョン 8 のコードを引き続き使用できます。つまり、アップグレード プロセスを進める際に、アプリのコンパイルとデバッグをより簡単に行うことができます。

Firebase Web SDK をほとんど使用していないアプリ(Authentication API の単純な呼び出しだけを行うアプリなど)では、バージョン 9 の互換ライブラリを使用せずに、バージョン 8 のコードをリファクタリングするほうが現実的です。このようなアプリをアップグレードする場合は、互換ライブラリを使用せずに、このガイドの「バージョン 9 モジュラー」の手順に沿ってください。

アップグレード プロセスについて

アップグレード プロセスの各ステップは、アプリのソースの編集を完了してから、エラーなしでコンパイルして実行できるように、スコープが設定されています。アプリのアップグレードの大まかな流れは次のとおりです。

  1. バージョン 9 のライブラリと互換ライブラリをアプリに追加します。
  2. コードのインポート ステートメントを v9 互換に更新します。
  3. 単一プロダクト(Authentication など)のコードをモジュラー スタイルにリファクタリングします。
  4. 省略可: 次に進む前に、Authentication のアプリサイズに関するメリットを実現するために、この時点で Authentication の互換ライブラリと Authentication の互換コードを削除します。
  5. 各プロダクト(Cloud Firestore、FCM など)の機能をモジュラー スタイルにリファクタリングし、すべての領域が完了するまでコンパイルとテストを行います。
  6. 初期化コードをモジュラー スタイルに更新します。
  7. 残っているバージョン 9 互換ステートメントと互換コードをアプリからすべて削除します。

バージョン 9 SDK を入手する

はじめに、npm を使用してバージョン 9 のライブラリと互換ライブラリを入手します。

npm i firebase@9.22.1

# OR

yarn add firebase@9.22.1

インポートの v9 互換への更新

依存関係を v8 から v9 ベータ版に更新した後もコードが引き続き動作するためには、インポート ステートメントを変更して、各インポートの「互換」バージョンを使用します。次に例を示します。

変更前: バージョン 8

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

変更後: バージョン 9 互換

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

モジュラー スタイルへのリファクタリング

バージョン 8 の API はドットチェーンの名前空間とサービス パターンに基づいていますが、バージョン 9 のモジュラー アプローチでは、原則的に関数を中心にコードを記述します。バージョン 9 では、firebase/app パッケージやその他のパッケージは、パッケージのすべてのメソッドを含む包括的なエクスポートを返しません。代わりに、パッケージの個々の関数がエクスポートされます。

バージョン 9 では、最初の引数としてサービスが渡され、関数はサービスの詳細を使用して残りの処理を行います。Authentication API と Cloud Firestore API の呼び出しをリファクタリングする 2 つの例で、その仕組みを見てみましょう。

例 1: Authentication の関数のリファクタリング

変更前: バージョン 9 互換

バージョン 9 互換コードはバージョン 8 コードと同じですが、インポートは変更されています。

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

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

変更後: バージョン 9 モジュラー

getAuth 関数は最初のパラメータとして firebaseApp を受け取ります。onAuthStateChanged 関数は、バージョン 8 とは異なり、auth インスタンスからチェーンされません。これは独立した関数であり、最初のパラメータとして auth を受け取ります。

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

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

認証メソッド getRedirectResult の処理を更新する

バージョン 9 では、getRedirectResult に互換性を破る変更が行われました。リダイレクト オペレーションが呼び出されない場合、バージョン 8 では null ユーザーを含む UserCredential が返されましたが、バージョン 9 では null が返されます。

変更前: バージョン 9 互換

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

変更後: バージョン 9 モジュラー

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 の関数のリファクタリング

変更前: バージョン 9 互換

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

変更後: バージョン 9 モジュラー

getFirestore 関数は最初のパラメータとして firebaseApp を受け取ります。これは、前の例の initializeApp から返されたものです。クエリを形成するコードは、バージョン 9 では大きく異なります。チェーンはなく、querywhere などのメソッドは独立した関数として公開されるようになりました。

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 への参照の更新

バージョン 9 ではプロパティ firestore.DocumentSnapshot.existsメソッドに変更されました。これは互換性を破る変更です。機能は基本的に同じ(ドキュメントが存在するかどうかのテスト)ですが、次に示すように v9 ではメソッドを使用するようにコードをリファクタリングする必要があります。

変更前: バージョン 9 互換

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

変更後: バージョン 9 モジュラー

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

例 3: バージョン 8 とバージョン 9 のコードスタイルの組み合わせ

アップグレード時に互換ライブラリを使用すると、バージョン 9 用にリファクタリングされたコードとともにバージョン 8 コードを引き続き使用できます。つまり、Cloud Firestore 用の既存のバージョン 8 コードを維持したまま、Authentication や他の Firebase SDK のコードをバージョン 9 スタイルにリファクタリングし、両方のコードスタイルを混在させたままアプリを正常にコンパイルできます。Cloud Firestore などの 1 つのプロダクトの中でも、バージョン 8 とバージョン 9 のスタイルを混在させることができます。ただし、ここでは互換パッケージをインポートすることが条件となります。

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

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

なお、アプリが正常にコンパイルされたとしても、アプリから互換ステートメントと互換コードを完全に削除するまでは、モジュラー コードで得られるアプリサイズのメリットは得られないことに注意してください。

初期化コードの更新

新しいモジュラー形式のバージョン 9 構文を使用するようにアプリの初期化コードを更新します。アプリ内のすべてのコードのリファクタリングを完了した後に、このコード更新を行うことが重要です。これは、firebase.initializeApp() は互換 API とモジュラー API の両方のグローバル状態を初期化するのに対して、モジュラー形式の initializeApp() 関数はモジュラーの状態のみを初期化するためです。

変更前: バージョン 9 互換

import firebase from "firebase/compat/app"

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

変更後: バージョン 9 モジュラー

import { initializeApp } from "firebase/app"

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

互換コードの削除

バージョン 9 のモジュラー SDK のサイズの利点を実現するには、最終的にすべての呼び出しを上記のモジュラー スタイルに変換し、すべての import "firebase/compat/* ステートメントをコードから削除する必要があります。これを行うと、firebase.* グローバル名前空間への参照と、バージョン 8 SDK スタイルのすべてのコードがなくなります。

window から互換ライブラリを使用する

バージョン 9 の SDK は、ブラウザの window オブジェクトではなく、モジュールによって動作するように最適化されています。以前のバージョンのライブラリでは、window.firebase 名前空間を使用して Firebase の読み込みと管理を行うことが可能でした。この方法では未使用のコードを除去できないため、今後はおすすめしません。ただし、モジュラー ライブラリへのアップグレード パスをすぐに開始しない場合は、JavaScript SDK の互換バージョンを window で使用できます。

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

互換ライブラリは、内部ではモジュラー バージョン 9 のコードを使用していますが、バージョン 8 の SDK と同じ API によって機能を提供しています。したがって、詳しい使用方法については、バージョン 8 の API リファレンスとバージョン 8 のコード スニペットをそのまま参照できます。この方法を長期間にわたって使用するのではなく、完全なモジュラー形式のバージョン 9 ライブラリへのアップグレードを開始することをおすすめします。

バージョン 9 のメリットと制限事項

完全にモジュール化されたバージョン 9 には、以前のバージョンと比べて次のようなメリットがあります。

  • バージョン 9 では、アプリのサイズを劇的に小さくすることができます。最新の JavaScript モジュール形式を採用することで「ツリー シェイキング」の手法が可能になり、アプリで必要なアーティファクトのみをインポートできます。アプリによっては、バージョン 9 でツリー シェイキングを行うと、バージョン 8 を使用してビルドした同等のアプリよりも 80% も小さくなることがあります。
  • バージョン 9 は現行の機能開発のメリットを享受し続けます。一方で、バージョン 8 は今後のどこかの時点で凍結されます。