もくじ
前置き
わたしが初めてフロントをReact(Gatsby)バックをfirebaseで開発を進めた際に
沼に陥ってしまったところを備忘録として残しています。
わたしはこの問題の解決に丸2日費やしてしまったので同じように行き詰まってしまった方の
一助となれば幸いです。
(この記事は以前Qiitaにまとめた備忘録の再編集です。)
結論
build時にはwindowオブジェクトにアクセスできるようになってからfirebaseを初期化させる必要がある。
C.Cの開発環境
- MacBook Pro 13inch 2018
- gatsby: "^4.6.1",
- firebase: "^8.10.0",
- node :"v16.13.0"
- コードエディタ:visual studio code
firebaseをお手本通りに実装すると…
ファイルの階層
- src
- firebase.js
- App.js
※こんな置き方しないと思いますが説明を簡単にするためご容赦ください。
firebase.js
import firebase from "firebase"
const firebaseConfig = {
apiKey: "your apiKey",
authDomain:"your authDomain",
projectId: "your projectId",
storageBucket: "your storageBucket",
messagingSenderId: "your messagingSenderId",
appId: "your appId",
};
// Initialize Firebase
export const initFirebase = () => {
if (firebase.apps.length === 0) {
firebase.initializeApp(firebaseConfig);
}
};
App.js
import React from "react";
import { initFirebase } from "./firebase.js"
export default function AppPage() {
initFirebase()
return <a>HogeHoge</a>;
}
npm run buildすると…
npm run developでは問題なく開発サーバーが立ち上がるのに
npm run build すると以下のようなエラーが出てしまいます。
ERROR #95313
Building static HTML failed for path "/App/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
700 | * limitations under the License.
701 | */
> 702 | registerFunctions(firebase, fetch.bind(self));
| ^
703 | firebase.registerVersion(name, version);
704 | //# sourceMappingURL=index.esm.js.map
705 |
WebpackError: ReferenceError: self is not defined
何が原因なのか?
firebaseのinitilaizeApp()はWindowオブジェクトを参照しているが、GatsbyのbuildフェーズではWindowオブジェクトにアクセスできないため
つまりfirebaseライブラリがWindowオブジェクトが無いのにアクセスしようとしているのでエラーが出ていました。
解決方法
ファイルの階層
- src
- firebase.js
- useFirebase.js
- App.js
- gatsby-node.js
まずはWindowオブジェクトがなければfirebaseを初期化しないように書き換えます。
firebase.js
import firebase from "firebase/app";
import "firebase/auth";
const firebaseConfig = {
apiKey: "your apiKey",
authDomain:"your authDomain",
projectId: "your projectId",
storageBucket: "your storageBucket",
messagingSenderId: "your messagingSenderId",
appId: "your appId",
};
let instance = null;
export default function getFirebase() {
if (typeof window !== "undefined") {
if (instance) return instance;
instance = firebase.initializeApp(firebaseConfig);
return instance;
}
return null;
}
useFirebase.js
useFirebase.jsを作成しWindowオブジェクトがあればinstance変数にfirebaseインスタンスが入るようにします。Windowオブジェクトがなければnullが入ります。
import { useEffect, useState } from "react";
import getFirebase from "./firebase"; // import our getFirebase function
export default function useFirebase() {
const [instance, setInstance] = useState(null);
useEffect(() => {
setInstance(getFirebase());
}, []);
return instance;
}
App.js
以下のように記述することで通常通りfirebaseが使えるようになります。
ここでは変数firebaseにインスタンスが入っていれば自動でユーザー情報を取得されるようになっています。
import React from "react";
import useFirebase from "./useFirebase";
export default function AppPage() {
const firebase = useFirebase();
useEffect(() => {
if (!firebase) return;
return firebase.auth().onAuthStateChanged((user) => {
console.log('User:', user);
});
}, [firebase]);
// ...
}
gatsby-node.js
最後にgatsby-node.jsには以下の内容を追加します。
これはサーバーをレンダリングする際にfirebaseモジュールが悪さしないようダミーモジュールに置き換えています。
(ここはC.Cもしっかりと理解していません。)
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
if (stage === "build-html") {
actions.setWebpackConfig({
module: {
rules: [
{
test: /firebase/,
use: loaders.null(),
},
],
},
});
}
};
ここまでの編集を行ったらnpm run buildを実行してみてください。
きっと成功するはずです!
最後に
動けばいいのよ動けば…
参考サイト
https://github.com/gatsbyjs/gatsby/issues/8612