🚒

Next.js で Firebase JavaScript SDK を使えるようにする

2021/06/18に公開

これは Firebase 公式ドキュメントを紐解きながら Next.js で Firebase を使えるようにした個人的な記録記事です

Firebase を JavaScript プロジェクトに追加する

このガイドでは、Firebase JavaScript SDK をウェブアプリで使用する手順について説明します。

SDK = software development kit = ソフトウェア開発キット

前提条件

  • お好みのエディタをインストールします。
  • Google アカウントを使用して Firebase にログインします。

ステップ 1: Firebase プロジェクトを作成する

JavaScript アプリに Firebase を追加する前に、アプリに接続する Firebase プロジェクトを作成します。

Firebase プロジェクトの詳細や、プロジェクトにアプリを追加する際のベスト プラクティスについては、Firebase プロジェクトについて理解する をご覧ください。

ステップ 2: アプリを Firebase に登録する

ステップ 3: Firebase SDK を追加して Firebase を初期化する

Firebase には、さまざまな Firebase JavaScript SDK をアプリに追加できます。
バージョン8npm を使用する場合、 Firebase JavaScript SDK の部分的なインポートを構成し、必要な Firebase プロダクトのみを読み込むことができます。
バンドラ(Browserify や webpack など)を使用している場合は、必要に応じて import を使用して個々の Firebase プロダクトをインポートします。

  1. Firebase JavaScript SDK をインストールします。
npm i firebase
  1. 特定の Firebase プロダクト( Authentication や Cloud Firestore など)を含めるには、Firebase モジュールを import します。
// Firebase App ( Firebase SDK のコア部分)は必ず必要で、最初に import する必要があります。
import firebase from "firebase/app";

// 使用したい Firebase プロダクトを追加する。
import "firebase/auth";
import "firebase/firestore";
  1. アプリで Firebase を初期化します。
// TODO: Replace the following with your app's Firebase project configuration
// 以下を、あなたのアプリのFirebaseプロジェクトの構成に置き換えてください。

const firebaseConfig = {
  // ...
};

// Initialize Firebase ( Firebaseの 初期化 )
firebase.initializeApp(firebaseConfig);

ちなみに Next.js で公式通りにコードを書くと私の場合以下のエラーが表示されました

Server Error
FirebaseError: Firebase: Firebase App named 
'[DEFAULT]' already exists (app/duplicate-app).
This error happened while generating the page.
Any console logs will be displayed in the terminal window.

内容の日本語訳は以下のとおりです

Firebase App という名前 '[DEFAULT]'は既に存在します(app / duplicate-app)
このエラーは、ページの生成中に発生しました。

firebase のインスタンスは既に存在するから2重につくるなよ、という意味だと予想します
キャッシュに既にインスタンスが存在するとこのエラーになるかもしれません
なぜエラーが出るコードを公式が出しているのかはわかりません
自分のコードや環境になにか問題があるだけかもしれません
いずれにせよ、(自分が調べた範疇ですが)一般的に下記のようなコードが用いられるようです

// Firebaseのインスタンスが存在しない場合にのみ、インスタンスを作成します
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig)
}



以下、私のコード例です

// ↓ firebase SDK の Core を import
import firebase from 'firebase/app';
// ↓ auth と firestore を import
import 'firebase/auth';
import 'firebase/firestore';

const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
};
// Firebaseのインスタンスが存在しない場合にのみ、インスタンスを作成します
if (!firebase.apps.length) {
  firebase.initializeApp(firebaseConfig)
}
export const auth = firebase.auth();
export const db = firebase.firestore();

参考 )

  • 今回私が使用するものは authfirestore です
    よって、 firebaseConfig に必要なのは apiKey projectId appId authDomain です
    exportauthdb となっています
    firestoreenv のパラメーターが与えられていない理由はわかりませんが CLUD に問題はないようです
  • 私のディレクトリ構成は src / util / firebase.js です
    今回 Next.js を使用しているので、 Next.js のルールに則り firebaseConfig の記述に NEXT_PUBLIC_ を用いています

Firebase config object について

構成オブジェクト(特に、必須の Firebase オプション apiKey、projectId、appID)を手動で編集しないことをおすすめします。
これらの必須の「Firebase オプション」のいずれかで無効な値が指定されているか、値が欠落している状態でアプリを初期化すると、ユーザーに深刻な問題が発生することがあります。

タイポで酷い目にあわないよう、コピペで運用してください、ということだと思われます

すべてのサービスが有効になっている構成オブジェクトの形式は次のとおりです(これらの値は自動的に入力されます)。

const firebaseConfig = {
  apiKey: "API_KEY",
  authDomain: "PROJECT_ID.firebaseapp.com",
  databaseURL: "https://PROJECT_ID.firebaseio.com",
  projectId: "PROJECT_ID",
  storageBucket: "PROJECT_ID.appspot.com",
  messagingSenderId: "SENDER_ID",
  appId: "APP_ID",
};

値の例を含む構成オブジェクトを次に示します。

const firebaseConfig = {
  apiKey: "AIzaSyDOCAbC123dEf456GhI789jKl01-MnO",
  authDomain: "myapp-project-123.firebaseapp.com",
  databaseURL: "https://myapp-project-123.firebaseio.com",
  projectId: "myapp-project-123",
  storageBucket: "myapp-project-123.appspot.com",
  messagingSenderId: "01234567891",
  appId: "1:01234567891:web:1ab23cd4efgh5i67jk8l9n",
};
  • ローカル環境での動作用として、上記の内容を、今回の私の構成ファイル内の .env.local に当てはめるとするなら以下のようになります
    , は不要で、 " " は無くても動作に問題はないようです)
  • 本番環境用については、今回私は vercel にてデプロイしているので、 vercel に以下の例のように Environment variables (環境変数) へ保存してあります
NEXT_PUBLIC_FIREBASE_PUBLIC_API_KEY=AIzaSyDOCAbC123dEf456GhI789jKl01-MnO
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=myapp-project-123.firebaseapp.com
NEXT_PUBLIC_FIREBASE_PROJECT_ID=https://myapp-project-123.firebaseio.com
NEXT_PUBLIC_FIREBASE_APP_ID=1:23456789010:web:1ab23cd4efghi5j67kl8o9p

ステップ 4:(省略可)CLI をインストールし、Firebase Hosting にデプロイする

私は vercel でデプロイするので省略します

ステップ 5:アプリで Firebase にアクセスする

Firebase JavaScript SDK は、次の Firebase プロダクトをサポートしています。
それぞれのプロダクトの使用は任意であり、アクセス方法は以下に示すとおりです。

Firebase プロダクト 名称
Analytics firebase.analytics()
Authentication firebase.auth()
Cloud Firestore firebase.firestore()
Cloud Functions for Firebase Client SDK firebase.functions()
Cloud Messaging firebase.messaging()
Cloud Storage firebase.storage()
Performance Monitoring (beta release) firebase.performance()
Realtime Database firebase.database()
Remote Config (beta release) firebase.remoteConfig()

使用可能なライブラリ

Firebase プロダクト import 文の書き方
Firebase Core(必須) import "firebase/app";
アナリティクス import "firebase/analytics";
Authentication import "firebase/auth";
Cloud Firestore import "firebase/firestore";
Cloud Functions for Firebase Client SDK import "firebase/functions";
Cloud Messaging import "firebase/messaging";
Cloud Messaging を最適な環境で使用するには、Google アナリティクス用の Firebase SDK も追加します。
Cloud Storage import "firebase/storage";
Realtime Database import "firebase/database";
Remote Config を最適な環境で使用するには、Google アナリティクス用の Firebase SDK も追加します。
  • 今回私は AuthenticationCloud Firestore を使用します
    運用は前述しましたが、以下のように代入し、それぞれ auth db として使います
  • なお、公式にあるように firebase Core の import を import "firebase/app"; とした場合、私の場合以下のようなエラーになりました
ReferenceError: firebase is not defined

そのため、 import firebase from 'firebase/app'; としています
Core とそれ以外の import の記述に差異がある理由については不明です

// ↓ firebase SDK の Core を import
import firebase from 'firebase/app';
// ↓ auth と firestore を import
import 'firebase/auth';
import 'firebase/firestore';

export const auth = firebase.auth();
export const db = firebase.firestore();

Discussion