🔥
Next.jsとFirebaseで初回ロードでエラーが出る問題の解決
結論
これでエラーを吐かずにSSRのNext.jsでFirebaseの初期化を正常に行えます。
import fb from "firebase/app";
import "firebase/auth";
import 'firebase/firestore';
export const firebase = !fb.apps.length ? fb.initializeApp(config) : fb.app()
export const firestore = firebase.firestore()
解説
ReferenceError: navigator is not defined
Server Errorの対処法
どうやらNext.jsはサーバーサイドでレンダリングするタイミングがあるので、その時におかしな挙動になってしまうらしい。まだSSRに疎いのでたまに遭遇する。
最初は下記の記事を参考にwindowがundefinedの時は初期化しないようにした。
これを
// appの初期化
if (!firebase.apps.length) {
firebase.initializeApp(config);
firebase.analytics();
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL);
}
export default firebase
export const firestore = firebase.firestore();
こうする
// appの初期化
if (typeof window !== 'undefined' && !firebase.apps.length) {
firebase.initializeApp(config);
firebase.analytics();
firebase.auth().setPersistence(firebase.auth.Auth.Persistence.LOCAL);
}
export default firebase
export const firestore = firebase.firestore();
※ しかし、これではinitializeAppがどうだ〜と言うエラーが出てしまう
FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - call Firebase App.initializeApp() (app/no-app).
こちらはfirebase appを初期化してないので怒られてます。
さて、そうは言ってもサーバーサイドで初期化処理を行おうとするとエラーになるからな〜と思っていたらVercelのリポジトリでいい記事が有りました。
この記事で解決
今回はimportまで書きました。
firebaseのdefault importをfbと命名するのを採用
そして、appsのlengthが存在すれば初期化したfirebaseAppを返却
なければfirebaseAppをただ返却するだけのコードを書いたら解決しました。
import fb from "firebase/app";
import "firebase/auth";
import 'firebase/firestore';
export const firebase = !fb.apps.length ? fb.initializeApp(config) : fb.app()
export const firestore = firebase.firestore()
Discussion
自分も未だにつまづいているのですが、補足として
(typeof window == 'undefined')
のときはサーバーサイドでコードが走っている、ということのようですね。