Skip to content

FR Firestore - Manual cache manipulation, app wide offline with external backend #8796

Open
@Aetherall

Description

@Aetherall

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);
            },
          });
        }
      }
    }

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions