使用动态导入时,Firebase 实时数据库出现“服务不可用”错误

问题描述 投票:0回答:1

我正在尝试 在我的 Web 应用程序中动态导入 Firebase 实时数据库 (RTDB) 服务,以减少初始包大小(数据库功能仅适用于登录用户)。但是,当我尝试使用动态导入初始化 RTDB 服务时,我收到以下错误:

Uncaught (in promise) Error: Service database is not available
    at Jp.getImmediate (provider.ts:130:15)
    at VE (Database.ts:321:44)

跟踪错误的 Firebase 数据库方法是:

  /**
   *
   * @param options.identifier A provider can provide mulitple instances of a service
   * if this.component.multipleInstances is true.
   * @param options.optional If optional is false or not provided, the method throws an error when
   * the service is not immediately available.
   * If optional is true, the method returns null if the service is not immediately available.
   */
  getImmediate(options: {
    identifier?: string;
    optional: true;
  }): NameServiceMapping[T] | null;
  getImmediate(options?: {
    identifier?: string;
    optional?: false;
  }): NameServiceMapping[T];
  getImmediate(options?: {
    identifier?: string;
    optional?: boolean;
  }): NameServiceMapping[T] | null {
    // if multipleInstances is not supported, use the default name
    const normalizedIdentifier = this.normalizeInstanceIdentifier(
      options?.identifier
    );
    const optional = options?.optional ?? false;

    if (
      this.isInitialized(normalizedIdentifier) ||
      this.shouldAutoInitialize()
    ) {
      try {
        return this.getOrInitializeService({
          instanceIdentifier: normalizedIdentifier
        });
      } catch (e) {
        if (optional) {
          return null;
        } else {
          throw e;
        }
      }
    } else {
      // In case a component is not initialized and should/can not be auto-initialized at the moment, return null if the optional flag is set, or throw
      if (optional) {
        return null;
      } else {
        throw Error(`Service ${this.name} is not available`);
      }
    }
  }


/**
 *
 * @param app - FirebaseApp instance
 * @param name - service name
 *
 * @returns the provider for the service with the matching name
 *
 * @internal
 */
export function _getProvider<T extends Name>(
  app: FirebaseApp,
  name: T
): Provider<T> {
  const heartbeatController = (app as FirebaseAppImpl).container
    .getProvider('heartbeat')
    .getImmediate({ optional: true });
  if (heartbeatController) {
    void heartbeatController.triggerHeartbeat();
  }
  return (app as FirebaseAppImpl).container.getProvider(name);
} 

下面是演示该问题的最小示例:

main.js:

import { initializeApp } from 'firebase/app';
import { getAuth, onAuthStateChanged } from 'firebase/auth';

const firebaseConfig = {
    // ... Your Firebase config
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);

onAuthStateChanged(auth, async (user) => {
    if (user) {
        const rtdbModule = await import('./dist/js/dynamic.min.js');
        const db = rtdbModule.initDB(app); // Pass the initialized Firebase App here
        // Use the database instance afterward
        ...
    }
});

dynamic.js:

import { getDatabase } from 'firebase/database';

export function initDB(app) {
    console.log(app); // This logs the correct app instance
    const db = getDatabase(app);
    return db;
}

我想了解为什么会发生错误,以及是否有更好的方法来动态导入 RTDB 以节省包大小。

任何见解或建议将不胜感激!

javascript firebase firebase-realtime-database es6-modules
1个回答
0
投票

好的,所以问题出在我的代码捆绑上。在我的捆绑脚本中,我在两个单独的捆绑包中输出了代码:

main.js
dynamic.js (which only loaded the RTDB module and returned the result)

当我这样做时,我收到了

Service database is not available
错误,因为生成的动态模块 位于不同的命名空间中,并且不包含 Firebase 需要的全局变量或其他运行时标志。

我通过输出单个模块、使用 ES6 模块和代码分割来修复它:

捆绑设置:

     esbuild(
        {
          bundle: true,
          sourcemap: true,
          minify: true,
          format: "esm",
          splitting: true, // added this
          outdir: 'dist/js', // added this
        },
      )

现在,esbuild 可以识别动态导入并将其拆分为不同的文件 (dynamic.js),该文件具有正确的命名空间。


async function setUpAuthEvents(auth) {
    onAuthStateChanged(auth, async function (user) {
        if (user) {
            const rtdbModule = await import("./dynamic.js");
            rtdb = rtdbModule.initDB(fbApp);
            // rtdb can be used from now on...
...

输出文件:

main.js (doesn't include RTDB package)
dynamic.js 
chunk.js

最后,我将 main.js 作为模块加载:

<script type="module" src="dist/js/main.min.js"></script>
© www.soinside.com 2019 - 2024. All rights reserved.