如何将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依赖构造函数引用一致性,两个不同模块的同名构造函数会直接导致校验失败
常见触发场景:
- 共享库打包配置未正确externalize Firebase依赖,导致Firestore代码被打包进库中
- Next.js的模块解析策略(如客户端组件、monorepo依赖链接)引发模块重复加载
- 主项目与共享库的Firebase版本看似一致,但锁文件中实际存在子版本差异
解决方案
确保共享库完全externalize Firebase依赖
- 在共享库的打包配置(Vite/Rollup/Webpack)中,将
firebase/firestore及相关包加入external列表,让库直接使用主项目提供的依赖 - 确认package.json的
peerDependencies正确声明Firebase包及版本范围(如"firebase": "^9.0.0")
- 在共享库的打包配置(Vite/Rollup/Webpack)中,将
强制主项目与共享库使用同一Firebase版本
- 删除双方的
node_modules和锁文件,重新安装依赖 - monorepo项目可通过pnpm workspace或yarn workspaces强制依赖统一
- 删除双方的
替换
instanceof为Firebase官方类型判断函数
若无法彻底解决模块重复加载,可改用Firebase提供的类型检测函数(不依赖构造函数引用):import { isCollectionReference } from "firebase/firestore"; // 替换原有instanceof判断 console.log("+++ isCollectionReference?", isCollectionReference(collectionRef));
内容的提问来源于stack exchange,提问作者Thijs Koerselman
相关产品推荐
相关产品推荐

