Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase v9 FirebaseFirestore Error #7135

Closed
d7p opened this issue Mar 19, 2023 · 18 comments
Closed

Firebase v9 FirebaseFirestore Error #7135

d7p opened this issue Mar 19, 2023 · 18 comments

Comments

@d7p
Copy link

d7p commented Mar 19, 2023

OS: MacOS M2
Firebase: 9.17.2

I have been using firebase functions for a while and now want to build an admin UI to speed up some admin tasks. The Firebase Functions and the new UI are written in Typescript and using:

//package.json 
"typescript": "^4.5.4",
"firebase": "^9.17.2"

This is a simplified version of how I'm setting up the UI:

//firebaseSetup.ts
import {initializeApp} from "firebase/app";
import {getAnalytics} from "firebase/analytics";
import {getAuth, connectAuthEmulator} from "firebase/auth";
import {getFirestore, connectFirestoreEmulator} from "firebase/firestore";
import {getFunctions, connectFunctionsEmulator} from "firebase/functions";
import {getStorage, connectStorageEmulator} from "firebase/storage";

const firebaseConfig = {/*firebase configs*/};
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
export db;

In my react component I can all the db and get the expected results.

//Main.tsx
import {UserService} from "@myModule/Services";
import {db} from "../firebaseSetup";
import {collection, Firestore, getDocs, limit, query} from "firebase/firestore";

//React component stuff...

  console.log(db.type); //output: firebase
  const c = collection(db, "users");
  const q = query(c, limit(10));
  getDocs(q).then((docs) => {
    const ur = docs.docs.map((u) => {
      return u.data() as unknown as User;
    });
    setUsers(ur);
  });

But when i move the same logic to a separate module like below

//UserService.ts
import {User, attachedPlan} from "../helpers/user"; 
import {collections} from "../helpers/collectionsEnum";
/* eslint-disable-next-line*/
import {addDoc,
  collection,
  collectionGroup,
  deleteDoc,
  doc,
  getDoc,
  getDocs,
  getFirestore,
  limit,
  query,
  setDoc,
  Timestamp,
  updateDoc,
  where,
  writeBatch,
  Firestore
} from "firebase/firestore";

export async function list(db:Firestore, pagesize?: number|null): Promise<User[]> {
  pagesize = pagesize || 10;
  console.log(typeof db); //output: object
  const c = collection(db, collections.Users);
  const q = query(c, limit(pagesize));

  return getDocs(q).then(data => {
    return data.docs.map(user =>{
      return user.data() as unknown as User;
     }); 
  })
  .catch((err)=>{
    console.error(err);
    throw err;
  });
}
//Main.tsx
import {UserService} from "@myModule/Services";
import {db} from "../firebaseSetup";
import {collection, Firestore, getDocs, limit, query} from "firebase/firestore";

//React component stuff...

UserService.list(db).then( (users) => {
    setUsers(users);
  });

I get a runtime error:

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

When I check the type in Main.tsx it returns firestore but when i check the type in the UserService.ts module function it is an object. As im not using the lite version I can't see how I am even hitting this error.

Thank you for any help

@google-oss-bot
Copy link
Contributor

I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.

@tylim88
Copy link
Contributor

tylim88 commented Mar 23, 2023

this issue is similar to tylim88/FirelordJS#91 (comment)

so this is what happen:

  1. your bundler transpile import statement to require statement
  2. require('firebase/firestore') will import code from firestore-lite instead

my deduction is this only happen at development mode of tools like create-react-app, vite-react and etc, because nobody is complaining about the production bundle but I am not 100%

this issue exist since firebase v9.17.1

the solution is to NOT transpile import statement into require statement, but this is a sub optimal solution and may break a lot of thing

@dconeybe
Copy link
Contributor

@tylim88 Can you confirm that this bug does not exist in 9.17.0 and 9.16.0? If this bug was indeed introduced in 9.17.1 then it should be easy to figure out since 9.17.1 was just an emergency bugfix release with a tiny change compared to 9.17.0.

@d7p
Copy link
Author

d7p commented Mar 23, 2023

I removed 9.17 and installed 9.16.0 in both the UI and the module. While the typeof output is now firebase in Userservice.list() I still get the error. This is the same if it is a debug build or production build.

I also checked all the webpack and tsconfig settings and all are set to ES2022 and I checked the compiled output has import not require(). I also deleted the firebase/firestore/lite folder and cleaned dist directory to see if it would throw an error looking for the lite version but it complied fine and gave the same issue. So i'm not sure that it is a transpile issue.

@dconeybe
Copy link
Contributor

@d7p Thanks for checking 9.16.0. Could you update the code snippets in the opening post to include the relevant import statements? That is, the import statements for the Firebase functions and classes that are used in the code snippets and the inter-file dependencies. Thank you.

@d7p
Copy link
Author

d7p commented Mar 24, 2023

@dconeybe updated. if there is more context i can add let me know

@d7p
Copy link
Author

d7p commented Apr 1, 2023

@tylim88 do you have any other ideas what could be wrong with this?
I checked the import/require and tried removing /lite folder (see above). if there are more details i can provide or something else I can try let me know.

@tylim88
Copy link
Contributor

tylim88 commented Apr 2, 2023

@tylim88 do you have any other ideas what could be wrong with this? I checked the import/require and tried removing /lite folder (see above). if there are more details i can provide or something else I can try let me know.

unfortunately I am not free to help you now, but if you really need a quick solution, then I shamelessly recommend you to try my library FirelordJS, it is tested up to firebase v9.18 plus create-react-app or vite-react

@dconeybe
Copy link
Contributor

dconeybe commented Apr 3, 2023

@d7p Nothing in the code that you posted looks problematic to me. Would you be able to create a minimal reproduction app in a github repository that I could clone to reproduce this for myself?

@d7p
Copy link
Author

d7p commented Apr 10, 2023

Sorry this took a while I found other issues with that i was trying to do while creating this.
the repo reproducing this is here but I have found this won't work as intended anyway. the app and firestore, from firebase is not the same as those from firebase-admin so can just be passed to a business logic / data layer. 😢

FYI: Anyone try to do this just with functions you need to use a bundler or publish the package to npm as firebase doesn't upload the local modules folder.

@dconeybe
Copy link
Contributor

@d7p The reproduction app that you created... can I use it to reproduce your issue? Or are you saying that it does not reproduce the issue?

@d7p
Copy link
Author

d7p commented Apr 11, 2023

the app does reproduce the issue. you don't even need to run the firebase emulator. if you go to the hosting directory and run the npm run serve then you will see the error in the browser.
The other issue I mention is just for extra context for others finding this and why I have had to do another direction with my admin app

@tylim88
Copy link
Contributor

tylim88 commented Apr 14, 2023

@tylim88 Can you confirm that this bug does not exist in 9.17.0 and 9.16.0? If this bug was indeed introduced in 9.17.1 then it should be easy to figure out since 9.17.1 was just an emergency bugfix release with a tiny change compared to 9.17.0.

@dconeybe the issue started at v9.17.0, I tested with my library firelordjs@2.2.5 and react-script 5.0.1
the error looks something like this
image
this is because firelordjs is tramspile to commonjs, they all use require (check node_modules/firelordjs/dist)

what is working:

  1. firelordjs@2.2.5 + firebase@9.16.0
  2. firelordjs@2.2.6(es2020 module, built code use import instead of require, check node_modules/firelordjs/dist) + firebase@any

what is not working

  1. firelordjs@2.2.5 + firebase@9.17.0+

do note that firelordjs@2.2.5 + firebase@9.18.0+ produce a different error:

image

reproducible repository https://github.com/tylim88/troubleshooting-firebase

run npm start to see the error, the code is in src/App.ts

@hsubox76
Copy link
Contributor

Those errors are caused by 9.17.0, and that bug was fixed in 9.17.1: https://firebase.google.com/support/release-notes/js It's not a Firestore bug. If the focus is on Firestore bugs, the relevant difference should be 9.17.1 vs 9.16.0.

@d7p
Copy link
Author

d7p commented Apr 17, 2023

I was using 9.17.2 so shouldn't have had the 9.17.0 bug

@dconeybe
Copy link
Contributor

@d7p I was reading over your opening comment and noticed that in Main.tsx you are calling db.type to get the type and in UserService.ts you are calling typeof db and expecting those to produce the same value. The problem is that typeof db is always going to return "object" for any object.

Here is a sample node.js session that shows what I mean:

 % node
Welcome to Node.js v18.14.2.
Type ".help" for more information.
> typeof "hello"
'string'
> typeof 5
'number'
> typeof {}
'object'
> typeof new Array();
'object'
> const app = await import('firebase/app').then(mod => mod.initializeApp({ ... }));
undefined
> const db = await import('firebase/firestore').then(mod => mod.getFirestore(app));
undefined
> typeof db
'object'
> db.type
'firestore'

Above you mentioned

the typeof output is now firebase

but that doesn't make sense to me, unless react is doing some sort of transformation of typeof statements.

In any case, I'm going to take a look at your reproduction app now that you mentioned in a previous comment, #7135 (comment)

@dconeybe
Copy link
Contributor

@d7p Could you give more instructions for how to use your app https://github.com/d7p/Firebase-issue to reproduce this issue?

I did the following:

cd hosting
npm install
npm run serve

but it fails with this output:

 % npm run serve
npm ERR! Missing script: "serve"
npm ERR! 
npm ERR! To see a list of scripts, run:
npm ERR!   npm run

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/dconeybe/.npm/_logs/2023-04-20T20_16_30_405Z-debug-0.log

Please advise.

@dconeybe
Copy link
Contributor

Ok I was able to reproduce the problem by using npm run start instead of npm run serve. And I found the root cause, although I don't know how to fix it. The root cause is a bundling problem that is out-of-scope for me to assist with.

First, the file hosting/src/firebaseSetup.ts contains the following import:

import {getFirestore, connectFirestoreEmulator} from "firebase/firestore";

At runtime, this ends up calling getFirestore() in hosting/node_modules/@firebase/firestore/dist/index.esm2017.js, the Firestore bundle produced for the browser as an ES module.

Similarly, localModule/index.ts imports

import {collection, Firestore, getDocs, query, where} from "firebase/firestore";

However, at runtime, the collection() function that gets called is localModule/node_modules/@firebase/firestore/dist/index.cjs.js, the Firestore bundle produced for the browser but as a CommonJS module.

It is not supported to intermix objects from the ES module and CommonJS module bundles. This explains, at least in part, why the collection() function doesn't recognize the Firestore object that it is given.

But even if the localModule project was changed to use the ES module it seems that there would still be a problem because the localModule build bundles all of Firebase in its bundle and hosting also does the same thing. This means that there are two distinct Firestore classes in the ultimate bundle and an instance of one will not pass an instanceof check with the other class.

I'm not personally familiar enough with bundling and react so I cannot help solve this problem. Perhaps someone else can comment?

I'm going to close this issue, though, since there is no further follow-up required from the maintainers of this repository. Feel free to ask more questions or continue discussing with other but I won't be able to devote time to the fix unless this ends up being a problem with the code in this git repository.

@firebase firebase locked and limited conversation to collaborators Jun 1, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

7 participants