diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 740444cd7cbfb..37160306a8b2f 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -512,6 +512,22 @@ async function generateDynamicFlightRenderResult( onError, } ) + await waitAtLeastOneReactRenderTask() + + if ( + ctx.staticGenerationStore.pendingRevalidates || + ctx.staticGenerationStore.revalidatedTags || + ctx.staticGenerationStore.pendingRevalidateWrites + ) { + const promises = Promise.all([ + ctx.staticGenerationStore.incrementalCache?.revalidateTag( + ctx.staticGenerationStore.revalidatedTags || [] + ), + ...Object.values(ctx.staticGenerationStore.pendingRevalidates || {}), + ...(ctx.staticGenerationStore.pendingRevalidateWrites || []), + ]) + ctx.renderOpts.waitUntil = (p) => promises.then(() => p) + } return new FlightRenderResult(flightReadableStream, { fetchMetrics: ctx.staticGenerationStore.fetchMetrics, @@ -1084,7 +1100,8 @@ async function renderToHTMLOrFlightImpl( // If we have pending revalidates, wait until they are all resolved. if ( staticGenerationStore.pendingRevalidates || - staticGenerationStore.pendingRevalidateWrites + staticGenerationStore.pendingRevalidateWrites || + staticGenerationStore.revalidatedTags ) { options.waitUntil = Promise.all([ staticGenerationStore.incrementalCache?.revalidateTag( @@ -1193,7 +1210,8 @@ async function renderToHTMLOrFlightImpl( // If we have pending revalidates, wait until they are all resolved. if ( staticGenerationStore.pendingRevalidates || - staticGenerationStore.pendingRevalidateWrites + staticGenerationStore.pendingRevalidateWrites || + staticGenerationStore.revalidatedTags ) { options.waitUntil = Promise.all([ staticGenerationStore.incrementalCache?.revalidateTag( diff --git a/test/e2e/app-dir/revalidatetag-rsc/app/RevalidateViaForm.tsx b/test/e2e/app-dir/revalidatetag-rsc/app/RevalidateViaForm.tsx new file mode 100644 index 0000000000000..762d46859ca11 --- /dev/null +++ b/test/e2e/app-dir/revalidatetag-rsc/app/RevalidateViaForm.tsx @@ -0,0 +1,17 @@ +'use client' + +import { revalidate } from './actions/revalidate' + +export default function RevalidateViaForm({ tag }: { tag: string }) { + const handleRevalidate = async () => { + await revalidate(tag) + } + + return ( +
+ ) +} diff --git a/test/e2e/app-dir/revalidatetag-rsc/app/actions/revalidate.ts b/test/e2e/app-dir/revalidatetag-rsc/app/actions/revalidate.ts new file mode 100644 index 0000000000000..2fba1ff18f207 --- /dev/null +++ b/test/e2e/app-dir/revalidatetag-rsc/app/actions/revalidate.ts @@ -0,0 +1,11 @@ +'use server' + +import { revalidateTag } from 'next/cache' + +export const revalidate = async ( + tag: string +): Promise<{ revalidated: boolean }> => { + revalidateTag(tag) + + return { revalidated: true } +} diff --git a/test/e2e/app-dir/revalidatetag-rsc/app/layout.tsx b/test/e2e/app-dir/revalidatetag-rsc/app/layout.tsx new file mode 100644 index 0000000000000..716a8db36f52c --- /dev/null +++ b/test/e2e/app-dir/revalidatetag-rsc/app/layout.tsx @@ -0,0 +1,9 @@ +import { ReactNode } from 'react' + +export default function Root({ children }: { children: ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/e2e/app-dir/revalidatetag-rsc/app/page.tsx b/test/e2e/app-dir/revalidatetag-rsc/app/page.tsx new file mode 100644 index 0000000000000..e4ced2724de32 --- /dev/null +++ b/test/e2e/app-dir/revalidatetag-rsc/app/page.tsx @@ -0,0 +1,24 @@ +import RevalidateViaForm from './RevalidateViaForm' +import Link from 'next/link' + +export default async function Page() { + const data = await fetch( + 'https://next-data-api-endpoint.vercel.app/api/random', + { + next: { + tags: ['data'], + revalidate: false, + }, + } + ).then((res) => res.text()) + + return ( +Tag [{tag}] has been revalidated
+
+ To Home
+
+