apollo-client icon indicating copy to clipboard operation
apollo-client copied to clipboard

Merge multiple caches for restoration

Open jacobp100 opened this issue 2 years ago • 5 comments

We're looking at micro-frontends with SSR support. Currently each MFE is rendering a part of the page in React, and extracting the data.

Is there a way to extract the InMemoryCache for each MFE, merge them, then create a new single Apollo client on the client using this merged cache?

jacobp100 avatar Jun 08 '22 15:06 jacobp100

It looks like entityStore might support this merging behaviour already (here) - but when cache.restore() is called, the entity store is reset (here). If the entity store wasn't reset, would this handle the merging - or are there caveats to this?

jacobp100 avatar Jun 08 '22 15:06 jacobp100

Thank you for reporting this! I suggest posting this in our Apollo Community for guidance from other Apollo users, as other's may have input into your question. I'll also leave this open to see if the team has any insights as well.

jpvajda avatar Jun 09 '22 15:06 jpvajda

As a temporary solution maybe you can try something like this :

const mergeApolloCache = (mainClient: ApolloClient<NormalizedCacheObject>, client: ApolloClient<NormalizedCacheObject>) => {
  const newData = client.cache.extract();

  if (newData) {
    const currentStore: EntityStore = (mainClient.cache as any).data;

    // Extract of cache.replace code without the clear old cache part
    // https://github.com/apollographql/apollo-client/blob/83935e8e1ea2c3eb4a0f10fffbbfb4d51cfc02d2/src/cache/inmemory/entityStore.ts#L335
    const { __META, ...rest } = newData;
    Object.keys(rest).forEach(dataId => {
      currentStore.merge(dataId, rest[dataId] as StoreObject);
    });
    if (__META) {
      __META.extraRootIds.forEach(currentStore.retain, this);
    }
  }
};

I've tested a few cases and it seems to work fine.

jgan42 avatar Jun 15 '22 15:06 jgan42

I'm also a bit puzzled on how to have multiple services specifying their own cache configuration but having just 1 Apollo client for the whole application. It's not exactly MFE but it's lazy loaded modules which is basically almost the same thing at the end of the day.

Each lazy loaded module knows their cache policies but the root module doesn't. I can have an Apollo Client per lazy loaded module but then I would have to plug to the root Apollo Client cache somehow to be able to access root state like the logged in userId for instance. I've been googling for the past hour and can't find anything obvious. Feeling pretty stupid right now, lol

alfaproject avatar Aug 23 '22 02:08 alfaproject

The solution from @jgan42 works well - it's pretty much using the same code used internally for restoration

jacobp100 avatar Aug 23 '22 08:08 jacobp100