RSCs stuck in Suspense. What is the limit for data passed from a React Server Component to a client component? #75976
Unanswered
kjetilhartveit
asked this question in
App Router
Replies: 1 comment 1 reply
-
|
Do you have this locally too or just on production? |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
After upgrading to NextJS 15 (App router) some of my
<Suspense>boundaries (wrapping RSCs) were stuck showing theloading.tsx. I suspect it has something to do with Next's serialization/deserialization of data passed from server components to client components. It might not be directly related to upgrading to NextJS 15 though. Previously I usednext-superjson-pluginbut during the upgrade to v15 I had to disable it due to #72019 so now I'm relying on Next.js to do the serialization.Debugging it
After debugging it seems to happen when passing a certain treshold of too much data from a server component to a client component. See the attached screen recording (#1). When it's working correctly the RSC data is available in the DOM tree, but when passing a treshold the data is no longer to be found in the DOM tree and the UI is stuck indefinitely showing
loading.tsx. The issue seemed to happen when I created a production build as well.I think there are more twists to the story; I think I was able to make the data appear by making a unsignificant change in the source-code and triggering a HMR/rebuild. Perhaps also by clicking around and then coming back to the component in question.
Also, when I tried to reproduce the issue it was difficult because I didn't seem to hit a limitation when using a seemingly large amounts of data with arrays of objects (see attachment #2).
nextjs-serialization-issue-infinite-loading.mp4
nextjs-serialization-issue-infinite-loading-2.mp4
Perhaps me using something "unconventional" like a Map is part of the issue?
Interestingly me changing the map during testing from
myObject.lineup(this is a Map) toArray.from(myObject.lineup.entries())solved the issue. So I thought, using Map is the issue, but I wasn't able to reproduce the issue by adding a small Map. Perhaps the Map must be of a substantial size like the one I use (themyObject.lineup.entries()version gives about 2877 chars)?Solution?
First and foremost I'm looking for a solution. Reducing the amount of data sent to the client is one option and the one I'm going for right now. Obviously it's also better for the users, so it's a win-win. The downside is obviously the work I have to do which I didn't have to do before (superjson probably made me lazy so this is kind of a good thing although also makes me uneasy as I'd like to avoid it happening again).
Detection
However, what is disturbing to me is that I can't think of a consistent/repeatable way of detecting whenever I pass too much data to the client. If passing small amounts of data to the client is the goal, then I'd like to embed this into my workflow, e.g. via a lint rule or something - although I'm not sure around the technicalities around this as how do you statically determine if you pass too much data (impossible? Checking complexitity of the types seems ugh). I guess I could implement some sort of view model layer routine into my workflow (also ugh), although I'd like to avoid that especially when client components only need small amounts of data.
Otherwise, can we detect when client components don't render or when suspense is stuck? Should I do some tracking in
loading.tsx(doesn't seem like a great idea)? Does Suspense have a configurable timeout or something? I don't expect observability on the server to be helpful because there's nothing wrong with the data fetching, but rather when passing data from the server to the client. End-to-end tests checking all my stuff (I see those judging eyes)?Tips on how to reproduce?
Lastly I've considered creating an issue on this but I'm having some trouble reproducing the issue in a different repo. If anyone has any ideas then I'm happy to hear them. Unfortunately my current repository is closed source at the moment.
Beta Was this translation helpful? Give feedback.
All reactions