You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Firestore引用传递到本地链接模块?实例校验失败排查

问题:Firebase CollectionReference instanceof 校验失败(共享库场景)

我有一个工具函数,在本地代码库运行正常,接收CollectionReference和文档ID作为参数。但移到共享库后出现错误:

FirebaseError: Expected first argument to collection() to be a CollectionReference, a DocumentReference or FirebaseFirestore

CollectionReference无法通过firebase/firestore内部的instanceof校验,已确保所有位置导入的firebase/firestore版本一致,库导出的是标准ESM代码,仍无法解决。

共享库中的工具函数代码

import { CollectionReference, doc, getDoc } from "firebase/firestore";
import { useEffect, useState } from "react";
function useDocumentDataOnce(collectionRef, documentId) {
  const [data, setData] = useState();
  useEffect(() => {
    const fetchData = async () => {
      if (!documentId) {
        return;
      }
      console.log(
        "+++ collectionRef instanceof CollectionReference?",
        collectionRef instanceof CollectionReference
      );
      const ref = doc(collectionRef, documentId);
      const snapshot = await getDoc(ref);
      if (snapshot.exists()) {
        setData(snapshot.data());
      } else {
        throw new Error(`No document at ${collectionRef.path}/${documentId}`);
      }
    };
    fetchData().catch(console.error);
  }, [collectionRef, documentId]);
  return data;
}

本地代码库中可正常运行的相同逻辑代码

import { CollectionReference, doc, getDoc } from "firebase/firestore";
import { useEffect, useState } from "react";

export function useDocumentDataOnce<T>(
  collectionRef: CollectionReference,
  documentId?: string
) {
  const [data, setData] = useState<T>();

  useEffect(() => {
    const fetchData = async () => {
      if (!documentId) {
        return;
      }

      console.log(
        "+++ collectionRef instanceof CollectionReference?",
        collectionRef instanceof CollectionReference
      );

      const ref = doc(collectionRef, documentId);

      const snapshot = await getDoc(ref);
      if (snapshot.exists()) {
        setData(snapshot.data() as T);
      } else {
        throw new Error(`No document at ${collectionRef.path}/${documentId}`);
      }
    };

    fetchData().catch(console.error);
  }, [collectionRef, documentId]);

  return data;
}

Next.js页面中的使用方式

"use client";

import { db, useUserId } from "@/lib/firebase";
import { useDocumentDataOnce } from "failurebase";
import { collection } from "firebase/firestore";

type User = {
  displayName: string;
};

export default function UserProfilePage() {
  const userId = useUserId();
  const usersCollectionRef = collection(db, "users");

  const user = useDocumentDataOnce<User>(usersCollectionRef, userId);

  return <div>Hello {user?.displayName ?? "unknown"}</div>;
}

错误来自工具函数中的这一行:

const ref = doc(collectionRef, documentId);

Firebase JS SDK内部的校验逻辑(reference.ts第578行):

if (
      !(parent instanceof DocumentReference) &&
      !(parent instanceof CollectionReference)
    ) {
      throw new FirestoreError(
        Code.INVALID_ARGUMENT,
        'Expected first argument to collection() to be a CollectionReference, ' +
          'a DocumentReference or FirebaseFirestore'
      );
    }

问题原因

核心问题是重复加载了Firebase Firestore模块,导致共享库和主项目中使用的CollectionReference构造函数不是同一个实例:

  • 主项目中通过collection()创建的CollectionReference,来自主项目依赖的Firestore模块构造函数
  • 共享库中导入的CollectionReference类型,来自共享库解析到的另一份Firestore模块构造函数
  • JavaScript的instanceof依赖构造函数引用一致性,两个不同模块的同名构造函数会直接导致校验失败

常见触发场景:

  1. 共享库打包配置未正确externalize Firebase依赖,导致Firestore代码被打包进库中
  2. Next.js的模块解析策略(如客户端组件、monorepo依赖链接)引发模块重复加载
  3. 主项目与共享库的Firebase版本看似一致,但锁文件中实际存在子版本差异

解决方案
  1. 确保共享库完全externalize Firebase依赖

    • 在共享库的打包配置(Vite/Rollup/Webpack)中,将firebase/firestore及相关包加入external列表,让库直接使用主项目提供的依赖
    • 确认package.json的peerDependencies正确声明Firebase包及版本范围(如"firebase": "^9.0.0")
  2. 强制主项目与共享库使用同一Firebase版本

    • 删除双方的node_modules和锁文件,重新安装依赖
    • monorepo项目可通过pnpm workspace或yarn workspaces强制依赖统一
  3. 替换instanceof为Firebase官方类型判断函数
    若无法彻底解决模块重复加载,可改用Firebase提供的类型检测函数(不依赖构造函数引用):

    import { isCollectionReference } from "firebase/firestore";
    // 替换原有instanceof判断
    console.log("+++ isCollectionReference?", isCollectionReference(collectionRef));
    

内容的提问来源于stack exchange,提问作者Thijs Koerselman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 06:25:13