跨包传递 Firestore (v9) 实例

Passing Firestore (v9) instance across packages

我正在尝试将一些 Firestore 操作写入一个单独的包中,以便可以在不同的 Web 应用程序中导入和重复使用。我正在用不同的包构建一个 monorepo 并且我正在尝试使用 Firebase v9 用于以下示例:

packageA 我正在定义和导出一个 getPosts(db) 函数,该函数接受一个 Firestore 对象和 returns 一些来自给定数据库的帖子

// in 'packageA'
import { collection, getDocs, Firestore } from 'firebase/firestore';

export const getPosts = async (db: Firestore) => {
  console.log('Passed in db: ', db); // This correctly prints the passed in Firestore object

  try {
    const postsCollection = collection(db, 'posts'); // This function will throw
    const querySnapshot = await getDocs(postsCollection);

    return querySnapshot.docs.map((doc) => doc.data());
  } catch (e) {
    console.error('Error reading posts: ', e);
  }
}

在网络应用中,我正在初始化 Firebase 应用并导出 Firestore 实例

// firebase.js in 'web-app-1'
import { initializeApp } from 'firebase/app';
import { getFirestore } from 'firebase/firestore';

const firebaseConfig = { /* my Firebase config */ };

export const app = initializeApp(firebaseConfig);
export const db = getFirestore(app);

然后我尝试在组件中使用包中的 getPosts 函数...

// App.js in 'web-app-1'
import { db } from './firebase.js';
import { getPosts } from 'packageA';

let posts;

async function loadPosts() {
  try {
    posts = await getPosts(db);
  } catch (e) {
    console.error(e);
  }
}

loadPosts(); // throws an error

但我从 collection(db, 'posts') 调用

中收到以下错误

Error reading posts: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore

即使传入的数据库在控制台中正确打印(形成 getPosts 函数)

注意: 如果我复制整个 getPosts 函数并直接在网络应用程序中使用它(即不从另一个包导入它)那么它可以正常工作获取帖子。

它看起来像是版本 9 的错误,并且该方法正在尝试使用 Firebase 实时数据库而不是 Firestore,因此该方法正在为集合发送错误。

使用该函数时似乎忽略了它是 Firestore 的事实,所以我会直接将其发送到 Firebase support,因为包的形成方式似乎是主要问题。

我仔细查看了一下,发现 一个类似的问题也可以解决我的问题。

基本上我必须做的是在 packageA 中将 Firebase 指定为 peerDependency 并且 不将其包含在最终包 中。使用 packageA 的 Web 应用程序将包含 Firebase 作为常规 dependency

因此 package.json 文件如下所示

在实用程序包中

{
  "name": "packageA",
  "peerDependencies": {
    "firebase": "^9.6.3"
  }
}

然后在网络应用程序中

{
  "name": "web-app-1",
  "dependencies": {
    "firebase": "^9.6.3",
  }
}

这种方法对我的用例也很有意义,因为初始化 Firebase 应用程序的 Web 应用程序(而且只有 Web 应用程序)会将其包含在其捆绑包中。但是我可以想象,在其他一些用例中,这不是一个可能的解决方案。

尽管如此,我已按照建议将我的问题提交给 Firebase 支持,这是他们的答复:

We have received some similar cases and we are already working to solve this. However, it can take a while due the workload of the engineering team, please, be patient.

我目前遇到了同样的问题。解决方法是直接通过捆绑器导入文件。

请记住,这不是最佳选择,因为我必须再次在本机项目中安装包,因此需要一些手动维护

项目结构

  • 应用
    • 原生
    • 网络
    • 工具

这确保我的应用程序使用 native/node_modules/

中的 firebase 实例和包

Metro.config.js

`

const { getDefaultConfig } = require("@expo/metro-config");
const path = require("path");

const projectRoot = __dirname;
const workspaceRoot = path.resolve(__dirname, "../..");

const config = getDefaultConfig(__dirname);

const extraNodeModules = {
  '@aim/utils': path.resolve(__dirname + '/../../packages/utils'),
};
const watchFolders = [
  path.resolve(__dirname + '/../../packages/utils')
];

config.watchFolders = [workspaceRoot];
config.resolver.nodeModulesPath = [
  path.resolve(projectRoot, "node_modules"),
  path.resolve(workspaceRoot, "node_modules"),
];

module.exports = {
  transformer: {
    getTransformOptions: async () => ({
      transform: {
        experimentalImportSupport: false,
        inlineRequires: false,
      },
    }),
  }, 
  resolver: {
    extraNodeModules: new Proxy(extraNodeModules, {
      get: (target, name) =>
        //redirects dependencies referenced from common/ to local node_modules
        name in target ? target[name] : path.join(process.cwd(), `node_modules/${name}`),
    }),
  },
  watchFolders,
};

// module.exports = config;

`

让类型发挥作用(原生)

tsconfig.json `

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "jsx": "react-native",
    "lib": ["dom", "esnext"],
    "moduleResolution": "node",
    "noEmit": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "strict": true,
    "baseUrl": ".",
    "paths": {
      "@aim/utils/*": ["../../packages/utils/*"]
    }
  },
}

`