如何在 gatsby 中初始化 firebase?

IT技术 reactjs firebase webpack react-redux gatsby
2021-04-25 21:28:47

我一直坚持在使用 Redux 和 Redux-saga 的 gatsby 应用程序中使 firebase 工作。我知道存在,firebase-sagas但我正在尝试不使用它。

我正在尝试通过以下方式初始化 firebase 身份验证:

import * as firebase from 'firebase/app';
import 'firebase/auth';

export const app = firebase.initializeApp(
  {
    apiKey        : "apiKey",
    authDomain    : "project.firebaseapp.com",
    databaseURL   : "https://project.firebaseio.com",
    projectId     : "project",
    storageBucket : "project.appspot.com",
    appId         : "appId"
  }

)

export const authRef = () => app.auth(); //also tried: firebase.auth() and firebase.auth(app)
//firebase.auth returns a function, but firebase.auth() throws error

我有以下配置gatsby-node.js

const path = require('path');

exports.onCreateWebpackConfig = ({ actions, plugins, loaders, getConfig }) => {
  const config = getConfig()

  config.resolve = {
    ...config.resolve,
      mainFields: ['module', 'browser', 'main'],
      alias: {
        ...config.resolve.alias,
        ['firebase/app']       : path.resolve(__dirname, 'node_modules/firebase/app/dist/index.cjs.js'),
        ['firebase/auth']      : path.resolve(__dirname, 'node_modules/firebase/auth/dist/index.cjs.js'),
      }
  }

  actions.replaceWebpackConfig(config)
}

它引发了错误:

{ [M [Error]: The XMLHttpRequest compatibility library was not found.]
  code: 'auth/internal-error',
  message: 'The XMLHttpRequest compatibility library was not found.' }

我认为这是与 webpack 相关的一些问题。我希望对这个问题有任何见解:)

1个回答

由于 Gatsby 在服务器环境中构建页面,因此您无法在 Gatsby 构建期间访问 Firebase。Firebase 调用(使用 Web SDK)必须在用户处于浏览器/客户端环境中时发生。

这个问题的一个解决方案是创建一个像这样的函数:

firebase.js:

import firebase from '@firebase/app';
import '@firebase/auth';
import '@firebase/firestore';
import '@firebase/functions';

const config = {
   ... firebase config here
};

let instance;

export default function getFirebase() {
  if (typeof window !== 'undefined') {
    if (instance) return instance;
    instance = firebase.initializeApp(config);
    return instance;
  }

  return null;
}

该文件返回一个函数,如果用户有全局window可用(例如在浏览器上),则该函数返回 Firebase 的一个实例它还缓存 Firebase 实例以确保它无法再次重新初始化(以防用户更改您网站上的页面)。

在您的组件中,您现在可以执行类似以下操作:

import getFirebase from './firebase';

function MyApp() {
  const firebase = getFirebase();
}

由于 Gatsby 将在 期间尝试将此页面构建为 HTML gatsby build,因此firebaseconst 将返回 null,这是正确的,因为 Firebase Web SDK 无法在服务器环境中初始化。但是,要在您的网站上使用 Firebase,您需要等到 Firebase 可用(因此用户必须加载您的网站),因此我们可以使用 ReactsuseEffect钩子:

import React { useEffect } from 'react';    
import getFirebase from './firebase';

function MyApp() {
  const firebase = getFirebase();

  useEffect(() => {
    if (!firebase) return;

    firebase.auth().onAuthStateChanged((user) => { ... });
  }, [firebase]);
}

这是因为 Firebase 在浏览器环境中使用并且可以访问浏览器,这是 Web SDK 工作所必需的。

它确实有缺点;null当您需要 Firebase 显示内容时,您的组件必须返回,这意味着您在服务器上的 HTML 构建将不包含任何 HTML,它将通过客户端注入。但在大多数情况下,例如account页面,这很好。

如果您需要访问来自 Cloud Firestore 的数据以显示页面内容,您最好使用 Admin SDK 来获取内容并将其添加到 Gatsby 构建期间的 GraphQL。这样它就可以在构建期间在服务器上使用。

对不起,如果这是华夫饼或不清楚!