Description
Operating System
not applicable
Environment (if applicable)
web/ios/android/react-native
Firebase SDK Version
11.3.1
Firebase SDK Product(s)
Firestore
Project Tooling
firebase-sdk-js
react
react-native
react-native-firebase
cloud functions
cloud run
firestore
Detailed Problem Description
App wide offline using firebase sdk as a backend for optimistic compensations
Firestore by itself is a great solution for apps with simple business rules.
By adding an external backend, a lot of us have been able to bring real time to more complex systems.
I am using firestore as a projection store for the read models of a CQRS system.
This has proven to be a really efficient way to keep great flexibility on our models,
while keeping compatibility with our mobile users while they run on previous versions.
When using a backend, you cannot use one of the best features for users: Offline
Multiple projects (including the one im working on) have to rely on complex systems to make up for that loss.
Online, people advise to use redux
to store firestore data, and to add optimistic on top. I've also seen tanstack
libraries recommended for that.
Effectively, using those solutions means re-implement in userland what firebase already does incredibly well.
(often using questionable techniques, impacting performances, and always using at least twice the storage).
Those approaches also require having 2 implementations for each queries.
- One for firestore.
- One for whatever additionnal storage solution you went with.
And even with good design decisions and a clear vision for the frontend architecture, on a big project, it often becomes impractical If you are still trying to replicate the extent of reactiveness no-backend firebase
allows.
Why posting here ?
It seems firebase sdks are a few changes away from solving that particular problem.
Essentially, firebase could allow "cache" mutations, that are never sent to the server,
while still affecting cache, notifying listeners off affected queries.
I am not really sure about the best solution for it, but while trying to implement it myself, I found out some points of concern.
For it to be safe, it would probably need to block the dequeue of mutations sent to server.
The simplest way to avoid all conflicts would be a "readonly" mode on initialization.
Also, we need a way to discard that mutation, either because of a failure, or because we received a new snapshot that contains the results of the mutation, that has been produced by the external backend.
TLDR
How implementable would custom cache management be in firebase sdk ?
Would you consider exposing methods to allow a custom implementation of such system ?
Steps and code to reproduce issue
I could experiment pretty far by blocking write stream initialisation.
I got optimistic behavior working well, but It will decohere over time without allowing to manage cached mutations
const client = db._firestoreClient;
const store = client?._onlineComponents?.remoteStore;
if (!store) return;
for (const key in store) {
const value = store[key as keyof typeof store] as unknown;
if (typeof value !== "object" || value === null) continue;
if ("constructor" in value) {
if (value.constructor.name.includes("WriteStream")) {
Object.defineProperty(value, "state", {
get() {
return 1;
},
set(v) {
console.log(v);
},
});
}
}
}