-
Notifications
You must be signed in to change notification settings - Fork 36
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
Multiple useFragment
uses for same fragment data creates large transport size
#344
Comments
I fear there's no real way around that :( Let me try to explain: What you see here is not us transporting cache data - it's something different: we transport a snapshot of your hook, to prevent React rehydration errors. The problem here is twofold:
So there is a possible scenario where your The whole thing looks like this (taken from my RFC). sequenceDiagram
participant GQL as Graphql Server
box gray Server
participant SSRCache as SSR Cache
participant SSRA as SSR Component A
end
participant Stream
box gray Browser
participant BCache as Browser Cache
participant BA as Browser Component A
end
participant Data as External Data Source
SSRA ->> SSRA: render
activate SSRA
SSRA -) SSRCache: query
activate SSRCache
Note over SSRA: render started network request, suspend
SSRCache -) GQL: query A
GQL -) SSRCache: query A result
SSRCache -) SSRA: query A result
SSRCache -) Stream: serialized query A result
deactivate SSRCache
Stream -) BCache: add query A result to cache
SSRA ->> SSRA: render
Data -) BCache: cache update
SSRA ->> SSRA: other children of the suspense boundary still need more time
Note over SSRA: render successful, suspense finished
SSRA -) Stream: transport
deactivate SSRA
Stream -) BA: restore DOM
BA ->> BA: rehydration render
Note over BA: ⚠️ rehydration mismatch, data changed in the meantime
So, to prevent these hydration errors, we essentially snapshot the value a hook had at the time it rendered first on the server, transport that over, render it once with that value, and if it differs from the actual cache contents, we immediately rerender with the current cache contents. All to prevent that hydration mismatch 🤦 Now, the thing is: each of those is a snapshot of that individual hook, at that individual point in time. All of these are not the same object, and they could have slight variances. That said, we do have escape hatches you could use to try and add your own deduplication logic (and if you come up with something good, please share it!):
apollo-client-nextjs/packages/experimental-nextjs-app-support/src/ApolloNextAppProvider.ts Lines 48 to 66 in da4c6f8
|
@phryneas thanks for the quick and super-detailed response! This helps our understanding of this particular problem and the streaming functionality 10x. I'll close this since there's no action item here. |
Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better. |
👋🏻 We're working on optimizing our Next.js App Router usage as much as we can and came into some possibly unexpected behavior related to the streaming support offered by this package. If this turns out to be expected behavior, that'd still be useful for us to know as well 🙂
Overview
We rely on
useFragment
to deliver cache updates for singleton data (not unlike a setup similar to what's described byAllProducts
in this documentation) to many different components that are rendered at once. Despite the same fragment, each usage ofuseFragment
seems to contribute linearly to the size of the script tag that manages theApolloSSRDataTransport
in the browser as a part of the SSR streaming process. Since we are subscribing to updates for the same location in the cache, we'd expect some kind of deduplication or normalization to prevent so much redundancy.Example
You can find a reproducing project forked from this repo here.
In order to visualize the problem, follow these steps:
Run the project with
yarn dev
Navigate to the new page that uses just one
useFragment
call at:http://localhost:5001/cc/use-fragment/1
Inspect the page source /
ApolloSSRDataTransport
script tag for this pageA pretty-printed example is shown below:
In a new tab, navigate to the new page that uses 24 of the same
useFragment
call at:http://localhost:5001/cc/use-fragment/24
Inspect the page source /
ApolloSSRDataTransport
script tag for this page. Compare it to the results in step 2.i and see that it's considerably larger and full of mostly redundant informationFind a pretty-printed example below that includes 23 more duplicate entries for the same Poll data
Feel free to continue testing with as many fragments as you'd like to see how it affects the transport. The number of rendered items is configurable in the URL:
The text was updated successfully, but these errors were encountered: