mesqueeb / vuex-easy-firestore

Easy coupling of firestore and a vuex module. 2-way sync with 0 boilerplate!
https://mesqueeb.github.io/vuex-easy-firestore
MIT License
234 stars 28 forks source link

Feedback: Persistence and functions in the state #270

Open louisameline opened 4 years ago

louisameline commented 4 years ago

I'm back sooner than I expected to talk about data persistence in v-e-f :p

The concept of using vuex-persist (for example) is to cache the data in localStorage, indexedDB or something else for later use. Why load the data from Firebase again and again each time the user launches the app if hasn't changed? Since I persist the store locally, I plan to (not tested yet) open a connection like this to avoid downloading any data I already have: db.collection("cities").where("updatedAt", ">", lastUpdateWeAreAwareOf).onSnapshot(...).

You may ask, what about Firestore SDK's local cache?

I read Firestore's documentation about caching (there isn't much unless I missed it) and I don't feel confident relying on it.

  1. AFAIK, the Firestore SDK doesn't bother checking if distant data is actually fresher than what you already got, and it charges you a "read" anyway (am I wrong about this?). That's why the manual condition I stated above seems the way to go.
  2. Secondly, by design, I think it's better to rely on your own caching policy, managed directly by you in your Vuex instance. For example Firestore uses a LRU cache, which may be a good thing or not. And if tomorrow you choose to plug on a provider other than Firebase (which hopefully shouldn't be too painful since v-e-f provides abstraction), who knows how it will handle cache.

So, since I choose to persist the store myself, that's why I recommend setting Firestore's own cache to the minimum (and not disabling it completely, since it's needed to allow retries after call failures). Otherwise Vuex-persist and Firestore will fight for the available device space and persist data twice, which is silly.

For my own app (where there is little fresh data to load remotely), I calculated that persisting Vuex will save roughly 60% of my bills.

I shared this so you would be aware of this scenario in the future, but also because I see that you put a function and a promise in the store (in debounceTimer). When vuex-persist inlines the state to save it in localStorage, these can't be saved of course, and I ran into a bug. Hence the need to store only "inlinable" data in the state.

Thanks for reading!

mesqueeb commented 4 years ago

need some time to go over this, i'll comment here again later when I do

mesqueeb commented 4 years ago

@louisameline

Thanks for pointing this out:

I read Firestore's documentation about caching (there isn't much unless I missed it) and I don't feel confident relying on it. unless the user is offline, it doesn't seem to be used

I didn't know this, it's a big problem. :D I totally agree with everything you say here and will have to further investigate and think about how to improve this in v2.

louisameline commented 4 years ago

I was wrong, when you get a document, even if you are online, Firestore SDK does call the listener with the data in cache if it has it, then a second time with the data from the server when it got it. But still, it doesn't check the freshness and charges you for the read. I'll edit my original post

mesqueeb commented 4 years ago

We'll need to keep this in mind for v2.0

I think that this idea is brilliant and perhaps something we should do by default in 2.0:

Since I persist the store locally, I plan to (not tested yet) open a connection like this to avoid downloading any data I already have: db.collection("cities").where("updatedAt", ">", lastUpdateWeAreAwareOf).onSnapshot(...).

Or at least make it easy for the devs to do this on read actions when they have some sort of local persistence enabled.