vercel / next.js

The React Framework
https://nextjs.org
MIT License
127.48k stars 27.04k forks source link

When generateMetadata performs an asynchronous action, Suspense is not being rendered until generateMetadata finish #72935

Open ebidrey opened 1 week ago

ebidrey commented 1 week ago

Link to the code that reproduces this issue

https://github.com/ebidrey/suspense-generate-metadata

To Reproduce

To Reproduce

You can run this simple snippet

import { Suspense } from "react"

export async function generateMetadata() {
    const results = await fetch('https://postman-echo.com/delay/2');
    await results.json();
    return {
        title: 'Test',
        description: 'Test',
    }
}

async function PageContent() {
    const results = await fetch('https://postman-echo.com/delay/2');
    await results.json();
    return  <h1>Test</h1>
}

export default async function Page() {
    return (
        <Suspense fallback={<div>loading running 2 seconds later</div>} key={Math.random()}>
            <PageContent />
        </Suspense>
    )
}

It is also available in github repo

Current vs. Expected behavior

I expect suspense fallback to be activated immediately when the page request is made and then, the page and the metadata get streamed. Instead, page stucks for the amount of time the request to the api takes, showing nothing up to the request finished, degradating the user experience and not improving SEO in any way.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.0.0: Fri Sep 15 14:41:43 PDT 2023; root:xnu-10002.1.13~1/RELEASE_ARM64_T6000
  Available memory (MB): 16384
  Available CPU cores: 10
Binaries:
  Node: 20.9.0
  npm: 10.1.0
  Yarn: 1.22.10
  pnpm: N/A
Relevant Packages:
  next: 15.0.4-canary.14 // Latest available version is detected (15.0.4-canary.14).
  eslint-config-next: 15.0.4-canary.14
  react: 19.0.0-rc-380f5d67-20241113
  react-dom: 19.0.0-rc-380f5d67-20241113
  typescript: 5.6.3
Next.js Config:
  output: N/A

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

Metadata, Performance

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

next dev (local), next build (local), next start (local), Vercel (Deployed), Other (Deployed)

Additional context

Tested in latest canary and stable.

markcarroll commented 1 week ago

I've hit this same issue too. It has forced me to change all my page titles to generic static strings so that suspense fallback gets rendered.

ebidrey commented 6 days ago

I've hit this same issue too. It has forced me to change all my page titles to generic static strings so that suspense fallback gets rendered.

Sadly I can't do that. The site I'm working on has half million different pages and this would broke the SEO dramatically :/

svobik7 commented 2 days ago

I saw the same applies for new async API for request params or searchParams.

There is an explanation in "generateMetadata" function docs saying:

Next.js will wait for data fetching inside generateMetadata to complete before streaming UI to the client. This guarantees the first part of a streamed response includes tags.

It actually makes sense that page can be streamlined only after all metadata fetching is done.

But on the other hand it goes against this whole "await params" API change which says:

However, not all components depend on request-specific data, so it's unnecessary to wait for the request to render them. Ideally, the server would prepare as much as possible before a request arrives

In that case nothing can be prepared and streamlined to the client in advance when used together with async generateMetadata.

Is there any plan to improve this?