Gatsby + firebase build時のエラーを解決する

# 本題
Gatsbyとfirebaseを組み合わせて開発中にdevelopはできるのにbuildするとErrorになって困ったことありませんか？　　
この記事の解決策が皆様のお役に立てたら幸いです。

# 筆者の環境
- MacBook Pro 13inch 2018
- "gatsby": "^4.6.1",
- "firebase": "^8.10.0",
- "node" :"v16.13.0"

# 通常通り開発すると…
通常ですと以下の様な感じでに開発されているのではないでしょうか

```javascript
// 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);
  }
};

```

```JSX
// App.js
import React from "react";
import { initFirebase } from "./firebase.js"

export default function AppPage() {
  initFirebase()
  
  return <a>HogeHoge</a>;
}
```

これで `npm run develop`を実行すると　　
問題なく`http://localhost:8000/` で開発サーバーが立ち上がると思います。　　
　　
　　
しかし、`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
```
# 何が問題なのか

以下のページに同じ悩みを持つ人が集まってました。

https://github.com/gatsbyjs/gatsby/issues/8612

コメントの一部をGoogle翻訳にかけてみると…　　

`Firebaseには、ウィンドウオブジェクトを参照するinitializeAppメソッドがあります。 Gatsbyは、ビルドフェーズでウィンドウオブジェクトにアクセスできません。したがって、そのオブジェクトにアクセスできるようになるまで、Firebaseの初期化を遅らせる必要があります。コンポーネントのcomponentDidMountライフサイクルフックに動的にインポートすると、これが保証されます。しかし、これで問題の解決は終わりではありません。`

私は非エンジニアなので詳しいことはよくわかりません！　　
ただ一つ言えること、それは…
### Gatsbyとfirebaseはbuild時に相性が悪い！
とザックリ理解しました。
(動けばいいのよ動けば…)


# 解決策
まずfirebase.jsを書き換えてwindowオブジェクトがなければ初期化されないようにします。

```javascript
//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を新たに作成してください。
初期化したfirebaseインスタンスをStateにいれてます。

```javascript
//useFirebase.js
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;
}

```

firebaseを使うには以下のようにしてください。　　
これでいつもと同じようにfirebaseを利用することができます。

```JSX
// App.js
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に以下を記述します。

```javascript
exports.onCreateWebpackConfig = ({ stage, loaders, actions }) => {
  if (stage === "build-html") {
    actions.setWebpackConfig({
      module: {
        rules: [
          {
            test: /firebase/,
            use: loaders.null(),
          },
        ],
      },
    });
  }
};
```

何をしているかって？

https://github.com/mongodb/stitch-js-sdk/issues/381

一部google翻訳を掛けて引用します。

`サーバーのレンダリング中にfirebaseモジュールをダミーモジュールに置き換えるためにWebpack構成をカスタマイズします。`

### たぶんfirebaseが悪さしないようにダミーに置き換えてる…と思う

最後にもう一度言おう　　
　　
### 動けば良いのよ動けば…　　
　　
これで`npm run build`してみてください！　　
きっと成功するはずです！ 

# 最後に
私はここに躓いて丸２日ほど時間を費やしてしまいました。　　
皆様の一助となりましたら幸いです。　　
また、解決策の部分など詳しい方いらっしゃいましたら　　
コメント欄でご指摘ご教授いただけないでしょうか？　　
よろしくお願いいたします。

# 参考サイト
https://invertase.io/blog/firebase-with-gatsby　　

https://github.com/gatsbyjs/gatsby/issues/8612　　

https://stackoverflow.com/questions/62137663/gatsby-react-booking-calendar-webpackerror-referenceerror-self-is-not-defi?rq=1