LoginSignup
0
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-02-17

本題

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

筆者の環境

  • MacBook Pro 13inch 2018
  • "gatsby": "^4.6.1",
  • "firebase": "^8.10.0",
  • "node" :"v16.13.0"

通常通り開発すると…

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

// 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 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

何が問題なのか

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

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

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

私は非エンジニアなので詳しいことはよくわかりません!  
ただ一つ言えること、それは…

Gatsbyとfirebaseはbuild時に相性が悪い!

とザックリ理解しました。
(動けばいいのよ動けば…)

解決策

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

//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にいれてます。

//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を利用することができます。

// 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に以下を記述します。

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

何をしているかって?

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

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

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

最後にもう一度言おう  
  

動けば良いのよ動けば…  

  
これでnpm run buildしてみてください!  
きっと成功するはずです!

最後に

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

参考サイト

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0