Skip to content
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

Using a client-side promise on initial render hangs server stream #70371

Open
mordechaim opened this issue Sep 23, 2024 · 3 comments
Open

Using a client-side promise on initial render hangs server stream #70371

mordechaim opened this issue Sep 23, 2024 · 3 comments
Labels
bug Issue was opened via the bug report template. Lazy Loading Related to Next.js Lazy Loading (e.g., `next/dynamic` or `React.lazy`).

Comments

@mordechaim
Copy link

Link to the code that reproduces this issue

https://github.com/mordechaim/promise-stream

To Reproduce

  1. Start the application with npm run dev
  2. Click "hard navigation" link

Current vs. Expected behavior

I use use() to resolve the promise in a client component. If the page is a full page load, the suspended component never "wakes up", the browser's loading indicator keeps spinning and the initial response body never completes.

When building the application with next build it hangs as well, with the following error message:

> next build

  ▲ Next.js 15.0.0-canary.163

   Creating an optimized production build ...
 ✓ Compiled successfully
 ✓ Linting and checking validity of types    
 ✓ Collecting page data    
   Generating static pages (5/6)  [=   ]Failed to build /suspend/page: /suspend (attempt 1 of 3) because it took more than 60 seconds. Retrying again shortly.

The behavior is not present if any of those is true:

  • The promise is created on the server and passed to the client in unresolved state
  • The promise resolves before the initial render completes
  • The page is a soft navigation, namely, the promise wasn't pre-rendered on the server

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 10 Home
  Available memory (MB): 32674
  Available CPU cores: 8
Binaries:
  Node: 20.5.0
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 15.0.0-canary.163 // Latest available version is detected (15.0.0-canary.163).
  eslint-config-next: N/A
  react: 19.0.0-rc-5d19e1c8-20240923
  react-dom: 19.0.0-rc-5d19e1c8-20240923
  typescript: 5.3.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Lazy Loading

Which stage(s) are affected? (Select all that apply)

next dev (local), next build (local)

Additional context

No response

@mordechaim mordechaim added the bug Issue was opened via the bug report template. label Sep 23, 2024
@github-actions github-actions bot added the Lazy Loading Related to Next.js Lazy Loading (e.g., `next/dynamic` or `React.lazy`). label Sep 23, 2024
@abhi12299
Copy link
Contributor

abhi12299 commented Sep 25, 2024

Here's why this happens:

  • When a full page load happens, your page is rendered on the server (note that marking a page/component with "use client"; does not stop the nextjs server from rendering it on the server) and since there is a Suspense boundary, the fallback is used in the initial render of the page, which means that the initial HTML sent by the nextjs server includes the fallback component.
  • The promise was created on the server and will only be resolved when the page mounts, since the call to resolve() is in a useEffect.
  • When the nextjs server tries to render the children of Suspense, it is unable to proceed because the render depends on the resolved value of the promise.

Now, this works on client side routing because the page is marked with "use client";, due to which the server only sends the RSC payload (only the necessary code), and the promise is created on the client, and the mounting also happens immediately and Suspense children are able to be rendered.

The reason why this case The promise resolves before the initial render completes works should be clear from the explanation above, i.e. the Suspense children are able to be rendered on the server.

@mordechaim
Copy link
Author

mordechaim commented Sep 25, 2024

I can clearly tell the effect executes on the client (via console.log() in the reproduction code). But your explanation is plausible and makes a lot of sense.

So, is this a bug, or just the code pattern should instead be avoided?

@abhi12299
Copy link
Contributor

this does not seem to be a bug - seems like an anti-pattern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. Lazy Loading Related to Next.js Lazy Loading (e.g., `next/dynamic` or `React.lazy`).
Projects
None yet
Development

No branches or pull requests

2 participants