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

Passing a query to useCollection gives warning "could not get path of the data source" #1315

Open
Soviut opened this issue Feb 27, 2023 · 16 comments

Comments

@Soviut
Copy link
Contributor

Soviut commented Feb 27, 2023

Reproduction

coming soon

Steps to reproduce the bug

  1. Install [email protected]
  2. Run the following code
<script setup lang="ts">
const q = query(getCol('companies'), orderBy('createdAt', 'desc'))
const { data: companies, pending } = useCollection(q)
</script>

<template>
  <p v-if="!pending && companies.length === 0">No companies yet</p>
  <div v-for="company in companies" :key="company.id">{{ company.name }}</div>
</template>
  1. Observe that pending resolves early causing any templates that depend on it to flash momentarily before being replaced with data.
  2. Observe that the data loads and is ordered correctly.
  3. Check the logs for [VueFire SSR]: Could not get the path of the data source

Expected behavior

I would expect that passing a query to useCollection would behave the same as passing a raw collection.

  • pending would resolve when fully complete to avoid flashing any template fragments that depend on it
  • there would be no warning
  • data would load correctly

Actual behavior

  • pending resolves early, flashing "no companies yet" fragment before replacing with data
  • throws a warning in the console
  • data loads correctly from query, in correct order

Additional information

I set a breakpoint in the source. Here's the result in Chrome Dev Tools with some of the local context showing.

image

@posva
Copy link
Member

posva commented Mar 7, 2023

For queries, you need to pass an ssrKey to the options of useCollection(): https://vuefire.vuejs.org/guide/ssr.html#manual-ssr-keys

@Soviut
Copy link
Contributor Author

Soviut commented Mar 7, 2023

@posva I suppose it doesn't matter that I'm not using SSR?

@posva
Copy link
Member

posva commented Mar 7, 2023

Not yet 😄

} else {
// TODO: warn if in SSR context in other contexts than vite
if (process.env.NODE_ENV !== 'production' /* && import.meta.env?.SSR */) {
console.warn('[VueFire SSR]: Could not get the path of the data source')
}
}

@davidstackio
Copy link
Contributor

I'm also not using SSR (ssr: false in Nuxt config) and get this SSR related warning. Ideally, if no SSR is being used, there wouldn't be any warning related to it.

@BenJackGill
Copy link

BenJackGill commented Aug 3, 2023

+1 here. I am also seeing this warning and not using SSR at all. Using latest VueFire 3.1.13 version.

@MarkSonn
Copy link

does anyone know what the ssrKey actually is? can it just be a random value or is there somewhere specific to get it?

Copy link
Member

posva commented Sep 21, 2023

it must be a unique key across your application

@ChrisRoss5
Copy link

I'm not using SSR and I need to get rid of this warning. Please fix this.

@Soviut
Copy link
Contributor Author

Soviut commented Nov 13, 2023

I'm not using SSR and I need to get rid of this warning. Please fix this.

Demanding a maintainer fix something like this is not a good way to encourage them.

First, you should explain exactly why you need to get rid of the warning, because usually warnings don't affect anything.

Second, you can already get rid of the warnings based on the links to documentation above. For example https://vuefire.vuejs.org/guide/ssr.html#Manual-SSR-keys explains that you can manually set an SSR key. This will make it go away

useCollection(queryRef, { ssrKey: 'my-quiz' })

Finally, consider sponsoring Posva so that he can reach his sponsorship goal and work on his open source projects full time. https://github.com/sponsors/posva

@ChrisRoss5
Copy link

I wish there was a better way. Thanks for help.

@tlserver
Copy link
Contributor

How about adding more details to the warning message? The current warning, [VueFire SSR]: Could not get the path of the data source, is somewhat misleading.

  1. Many responses to this issue indicate that they are not using SSR, so the prefix [VueFire SSR] can be confusing.
  2. The message does not mention the ssrKey option. If providing an ssrKey is the preferred method of resolution, it might be helpful to include this in the warning.
  3. It would also be beneficial to reference documentation or an FAQ, such as https://vuefire.vuejs.org/guide/ssr.html#Manual-SSR-keys, directly in the warning message.

@BenJackGill
Copy link

BenJackGill commented Dec 28, 2023

From what I can gather they plan to fix this by hiding the message for those not using SSR. The fix just hasn't been released yet. Maybe creating a PR would be helpful for the repo owner.

Adding the ssrKey is a workaround until the fix is released.

@tewshi
Copy link

tewshi commented Aug 22, 2024

still experienced this, had to use @BenJackGill 's fix

@tewshi
Copy link

tewshi commented Aug 22, 2024

hopefully it is resolved here #1564

@sun
Copy link

sun commented Nov 19, 2024

Please correct me if I'm wrong, but my understanding is that this issue is not about removing the warning, but about the promise that resolves too early.

Actual/Expected behavior stated in the summary:

- pending resolves early, flashing "no companies yet" fragment before replacing with data
+ pending would resolve when fully complete to avoid flashing any template fragments that depend on it

The warning is just telling you that something isn't right.

In the given example, because useCollection() cannot bind the query without knowing a key to bind it to.

Without the warning the problem would possibly be hidden away without a chance to enter debugging.

The warning message is somewhat misleading, because it mentions the component "SSR". But the problem is not limited to SSR. It seems a more accurate warning message text would be:

Warning

[VueFire]: Unable to bind data source to a key by ref. Try passing a target or ssrKey.

But to actually resolve the problem, you need to pass a ref to bind to.

Either by passing a target; see https://vuefire.vuejs.org/cookbook/subscriptions-external.html#Binding-Firebase-Reference-to-existing-Vue-Refs

todos // given an existing Ref<Todo[]>
const { pending } = useCollection(todoListRef, { target: todos })

Or by passing an ssrKey; see https://vuefire.vuejs.org/guide/ssr.html#Manual-SSR-keys

useCollection(queryRef, { ssrKey: 'my-quiz' })

I believe I'm facing the issue myself where I'm trying to bind a query to a prop in a watch in a Vue 2 app I'm trying to upgrade to Vue 3 – although I'm not 100% sure. At least the stack traces are seemingly pointing to the very same places as in this issue.

const todosQuery = db.collection('todos')
  .where('category', 'array-contains', category)
  .orderBy('updated', 'desc');
this.$firestoreBind(`todos.${category}`, todosQuery); // ⚠️ [VueFire SSR]: Could not get the path of the data source

// ❌ Uncaught TypeError: snapshot.exists is not a function
//   at Object.fromFirestore (vuefire.js)
//   at _FirestoreDataConverter.fromFirestore (firebase_compat_firestore.js)

Both the warning and error remains when switching to useCollection() with any of the suggested options:

   this.todos[category] = useCollection(todosQuery);
// const todosRef = toRef(this.todos, category);
// this.todos[category] = useCollection(todosQuery, { target: todosRef });
// this.todos[category] = useCollection(todosQuery, { ssrKey: `todos.${category}` });

@sun
Copy link

sun commented Nov 22, 2024

The TypeError I was facing was unrelated; it is caused by using VueFire 3 together with the Firebase 10 namespaced/compat SDK. Configuring a global fromFirestore() converter using snapshot.exists (the property) instead of the function resolved it and my data finally appears now.

globalFirestoreOptions.converter = {
  toFirestore: firestoreDefaultConverter.toFirestore,
  fromFirestore(snapshot, options) {
    return snapshot.exists ? (Object.defineProperties(snapshot.data(options), { id: { value: snapshot.id } })) : null
  },
};

(see also this related Firebase compat SDK type mismatch issue)

However, I still see the warning with vuefire 3.2.0, even when passing an ssrKey. A breakpoint in deferInitialValueSetup() reveals that it cannot determine a sourceType via getDataSourceInfo():

image

This is because isFirestoreQuery() returns false for source.type === "query":

image

Seems the object (class _Query) is a proxy and somehow not forwarding the property value. This is beyond my understanding of JS Proxy objects and the involved APIs.

I fear this might also be related to using the Firebase compat libraries? I eventually want to upgrade to the modular SDK, but was hoping to first get the app fundamentally working again on Vue 3, leveraging the compat libraries, and doing the major code refactoring for Composition API and modular SDK only afterwards, as it's going to be a lot of labor. Downgrading to VueFire 2 doesn't seem possible, because it does not support Vue 3. And as far as I can see there is no VueFire compat library?

Sorry for the noise, everyone – by now I assume my case is special/different to yours due to the compat libraries. I did not want to hijack this issue, I genuinely thought I was facing the same problem. Maybe I should open a separate one. Mainly leaving this here in case someone else runs into the same issue.


Edit: The Query object is a delegate and not a proxy. The Firestore Query class defines the delegate itself, and delegation usually only forwards functions, not properties. So it seems this should be affecting everyone.

https://github.com/firebase/firebase-js-sdk/blob/ffbf5a60ac756c69dd50bddb69fccd9968844ac5/packages/firestore/src/lite-api/reference.ts#L115-L120
https://github.com/firebase/firebase-js-sdk/blob/ffbf5a60ac756c69dd50bddb69fccd9968844ac5/packages/firestore/src/lite-api/reference.ts#L174-L178

A workaround for the isFirestore… checkers would be to just check for the type property on the delegate, too?

-  return isObject(source) && source.type === 'query'
+  return isObject(source) && (source.type === 'query' || (source._delegate && source._delegate.type === 'query'))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants