Open abstractvector opened 1 year ago
This also happens using the new generateMetadata
approach too. https://github.com/vercel/next.js/discussions/41745#discussioncomment-4886739
I've updated my reproduction repository to show the same behavior using the metadata
/ generateMetadata()
architecture: https://github.com/abstractvector/nextjs-issue-async-head/tree/metadata
I also experience the same issue.
I'm having the same problem using the same API fetch for generateMetadata
and the main page. Even for a relatively fast API fetch, the page still appears very slow without any loading.js
to give an immediate UI response to the user's route change.
This behaviour is mentioned as intentional at: https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming
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.
Whilst this makes sense for the initial page load so the correct head elements are returned to crawlers etc., I would think subsequent navigations within the app shouldn't need to wait for generateMetadata
to complete as the head could be updated at any point during a subsequent page load, which would allow loading.js
to render immediately and give a much better UX.
Perhaps an option in next.config.js
or an exported variable in page.js
that changes the behaviour not to wait for generateMetadata
to begin streaming, other then for the initial page load.
@huozhi in https://github.com/vercel/next.js/issues/45106#issuecomment-1440040679 on Feb 22 you mentioned in relation to this problem:
but we're also planning to patch the matdata separately to make navigation faster
Could you kindly advise if this patch has already been applied to the latest release or is still in the works? As the blocking generateMetadata problem still occurs, but I wasn't sure if we're still waiting on the patch or whether the patch didn't solve this particular issue. Thanks in advance
@Fredkiss3 https://github.com/vercel/next.js/issues/43548#issuecomment-1574138714 proposes a hack to return empty metadata for navigations after the initial load, and dynamically change the metadata in each page.js
on the client side.
It may not be production-ready, but it would be good to see this sort of functionality available in the Next.js framework.
Still having this issue in Next 14.1. My generateMetadata
function makes an async call to get the name of the resource being shown on the page to show in the title, which prevents my loading.tsx
skeleton screen from showing on page transitions until the request completes.
In the meantime, here is my hacky solution inspired by @Fredkiss3
// getMetadataWithFallback.ts
import { Metadata } from 'next';
import { headers } from 'next/headers';
function isSSR() {
return headers().get('accept')?.includes('text/html'); // for RSC navigations, it uses either `Accept: text/x-component` or `Accept: */*`, for SSR browsers and other client use `Accept: text/html`
}
const fallback: Metadata = {
title: 'Loading...',
};
type GenerateMetadata<T> = (params: T) => Promise<Metadata>;
const getMetadataWithFallback =
<Params>(
generateMetadata: GenerateMetadata<Params>,
staticMetadata?: Partial<Metadata>
) =>
(params: Params) => {
return isSSR()
? generateMetadata(params)
: Promise.resolve({ ...fallback, ...staticMetadata });
};
export default getMetadataWithFallback;
Usage:
// page.tsx
export const generateMetadata = getMetadataWithFallback(
// your async generateMetadata function here
)
Finally, a hook to update the title from a client component once the data is fetched
// useUpdateTitle.ts
import { useLayoutEffect } from 'react';
export default function useUpdateTitle(title?: string) {
useLayoutEffect(() => {
if (title) {
document.title = title;
}
}, [title]);
}
Same issue here. Currently there appears to be no standard way of showing a loading state while generateMetadata
is executing. I'll try the workaround above for now.
Any update? generateMetadata is blocking the UI
Same issue
Edit by maintainer bot: Comment was automatically minimized because it was considered unhelpful. (If you think this was by mistake, let us know). Please only comment if it adds context to the issue. If you want to express that you have the same problem, use the upvote 👍 on the issue description or subscribe to the issue for updates. Thanks!
@riley-worthington - thanks for sharing your solution.
Do you mind explaining why useUpdateTitle.ts
uses useLayoutEffect
instead of useEffect
?
Guys, I have found a fix for this whom may be looking:
Issue: loading.tsx not showing when metadata is fetching (showing blank instead of loading component).
If it uses client, it does not stream loading component from server when needed.
If you need somehow access path, etc. from request, use middleware + headers.
P/s: recommend to implement along with https://github.com/vercel/next.js/issues/45418#issuecomment-1914076788.
Max
Verify canary release
Provide environment information
Which area(s) of Next.js are affected? (leave empty if unsure)
App directory (appDir: true)
Link to the code that reproduces this issue
https://github.com/abstractvector/nextjs-issue-async-head
To Reproduce
Create a
head
file in an appDir API route (e.g../src/app/blog/[slug]/head.tsx
) that returns a default async function. Create aloading.tsx
file or similar alongside it.Describe the Bug
The loading component (e.g.
./src/app/blog/[slug]/loading.tsx
) will not be displayed until the head component has rendered. Likewise, the URL will not be updated until the head component has rendered.If both the head and page components are calling the same APIs to retrieve data (likely a common use case, and one specifically referenced in the documentation), then the loading layer will never show.
Expected Behavior
As soon as the user clicks the link, the URL should update and the loading layer should be displayed.
Which browser are you using? (if relevant)
Firefox 109.0
How are you deploying your application? (if relevant)
next start