From c7e14144ff43a9c2ff84b87dc4564a746e58f295 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 1 Mar 2023 22:18:49 -0800 Subject: [PATCH 1/2] Fix static to dynamic on revalidate --- packages/next/src/server/lib/patch-fetch.ts | 13 ++++-- .../e2e/app-dir/app-static/app-static.test.ts | 38 +++++++++++++++++ .../[slug]/page.js | 42 +++++++++++++++++++ 3 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index f828e5dce6c0f..1be45905b609d 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -78,10 +78,12 @@ export function patchFetch({ getRequestMeta('method')?.toLowerCase() || 'get' ) + const autoNoCache = hasUnCacheableHeader || isUnCacheableMethod + if (typeof revalidate === 'undefined') { // if there are uncacheable headers and the cache value // wasn't overridden then we must bail static generation - if (hasUnCacheableHeader || isUnCacheableMethod) { + if (autoNoCache) { revalidate = 0 } else { revalidate = @@ -93,9 +95,12 @@ export function patchFetch({ } if ( - typeof staticGenerationStore.revalidate === 'undefined' || - (typeof revalidate === 'number' && - revalidate < staticGenerationStore.revalidate) + // we don't consider autoNoCache to switch to dynamic during + // revalidate although if it occurs during build we do + (!autoNoCache || !staticGenerationStore.isRevalidate) && + (typeof staticGenerationStore.revalidate === 'undefined' || + (typeof revalidate === 'number' && + revalidate < staticGenerationStore.revalidate)) ) { staticGenerationStore.revalidate = revalidate } diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index 54cf0f431867a..35cfeee3a585f 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -58,6 +58,9 @@ createNextDescribe( 'force-static/page.js', 'force-static/second.html', 'force-static/second.rsc', + 'gen-params-dynamic-revalidate/[slug]/page.js', + 'gen-params-dynamic-revalidate/one.html', + 'gen-params-dynamic-revalidate/one.rsc', 'gen-params-dynamic/[slug]/page.js', 'hooks/use-pathname/[slug]/page.js', 'hooks/use-pathname/slug.html', @@ -191,6 +194,11 @@ createNextDescribe( initialRevalidateSeconds: false, srcRoute: '/force-static/[slug]', }, + '/gen-params-dynamic-revalidate/one': { + dataRoute: '/gen-params-dynamic-revalidate/one.rsc', + initialRevalidateSeconds: 3, + srcRoute: '/gen-params-dynamic-revalidate/[slug]', + }, '/ssg-preview': { dataRoute: '/ssg-preview.rsc', initialRevalidateSeconds: false, @@ -246,6 +254,16 @@ createNextDescribe( fallback: null, routeRegex: '^\\/dynamic\\-error\\/([^\\/]+?)(?:\\/)?$', }, + '/gen-params-dynamic-revalidate/[slug]': { + dataRoute: '/gen-params-dynamic-revalidate/[slug].rsc', + dataRouteRegex: normalizeRegEx( + '^\\/gen\\-params\\-dynamic\\-revalidate\\/([^\\/]+?)\\.rsc$' + ), + fallback: null, + routeRegex: normalizeRegEx( + '^\\/gen\\-params\\-dynamic\\-revalidate\\/([^\\/]+?)(?:\\/)?$' + ), + }, '/hooks/use-pathname/[slug]': { dataRoute: '/hooks/use-pathname/[slug].rsc', dataRouteRegex: normalizeRegEx( @@ -793,6 +811,26 @@ createNextDescribe( } }) + it('should not error with generateStaticParams and authed data on revalidate', async () => { + const res = await next.fetch('/gen-params-dynamic-revalidate/one') + const html = await res.text() + expect(res.status).toBe(200) + expect(html).toContain('gen-params-dynamic/[slug]') + expect(html).toContain('one') + const initData = cheerio.load(html)('#data').text() + + await check(async () => { + const res2 = await next.fetch('/gen-params-dynamic-revalidate/one') + + expect(res2.status).toBe(200) + + const $ = cheerio.load(await res2.text()) + expect($('#data').text()).toBeTruthy() + expect($('#data').text()).not.toBe(initData) + return 'success' + }, 'success') + }) + it('should honor dynamic = "force-static" correctly', async () => { const res = await next.fetch('/force-static/first') expect(res.status).toBe(200) diff --git a/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js b/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js new file mode 100644 index 0000000000000..7476245fbf597 --- /dev/null +++ b/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js @@ -0,0 +1,42 @@ +export const revalidate = 3 + +export async function generateStaticParams() { + return [{ slug: 'one' }] +} + +const fetchRetry = async (url, init) => { + for (let i = 0; i < 5; i++) { + try { + return await fetch(url, init) + } catch (err) { + if (i === 4) { + throw err + } + console.log(`Failed to fetch`, err, `retrying...`) + } + } +} + +export default async function page({ params }) { + const { slug } = params + let data + + if (process.env.NEXT_PHASE !== 'phase-production-build') { + data = await fetchRetry( + 'https://next-data-api-endpoint.vercel.app/api/random', + { + headers: { + Authorization: 'Bearer my-token', + }, + } + ).then((res) => res.text()) + } + + return ( + <> +

/gen-params-dynamic/[slug]

+

{slug}

+

{data}

+ + ) +} From 9f5bf1fdac7f328661b860d55f90519d25608cd6 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 1 Mar 2023 22:46:32 -0800 Subject: [PATCH 2/2] add/leverage isPrerendering field --- .../src/client/components/static-generation-async-storage.ts | 1 + packages/next/src/export/worker.ts | 1 + .../async-storage/static-generation-async-storage-wrapper.ts | 2 ++ .../src/server/future/route-handlers/app-route-route-handler.ts | 1 + packages/next/src/server/lib/patch-fetch.ts | 2 +- 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/next/src/client/components/static-generation-async-storage.ts b/packages/next/src/client/components/static-generation-async-storage.ts index 9977c0e07040d..071550da42316 100644 --- a/packages/next/src/client/components/static-generation-async-storage.ts +++ b/packages/next/src/client/components/static-generation-async-storage.ts @@ -6,6 +6,7 @@ export interface StaticGenerationStore { readonly pathname: string readonly incrementalCache?: import('../../server/lib/incremental-cache').IncrementalCache readonly isRevalidate?: boolean + readonly isPrerendering?: boolean forceDynamic?: boolean revalidate?: false | number diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index bdf9a5940799d..151eeb9db0ac1 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -385,6 +385,7 @@ export default async function exportPage({ `http://localhost:3000${req.url}` ) const staticContext: StaticGenerationContext = { + nextExport: true, supportsDynamicHTML: false, incrementalCache: curRenderOpts.incrementalCache, } diff --git a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts index 5c2ae6d505c31..111672123f142 100644 --- a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts @@ -10,6 +10,7 @@ export type RequestContext = { supportsDynamicHTML: boolean isRevalidate?: boolean isBot?: boolean + nextExport?: boolean } } @@ -53,6 +54,7 @@ export class StaticGenerationAsyncStorageWrapper pathname, incrementalCache: renderOpts.incrementalCache, isRevalidate: renderOpts.isRevalidate, + isPrerendering: renderOpts.nextExport, } ;(renderOpts as any).store = store diff --git a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts index 671cd8c88e4f4..5e513b7541df5 100644 --- a/packages/next/src/server/future/route-handlers/app-route-route-handler.ts +++ b/packages/next/src/server/future/route-handlers/app-route-route-handler.ts @@ -94,6 +94,7 @@ export type AppRouteModule = { export type StaticGenerationContext = { incrementalCache?: IncrementalCache supportsDynamicHTML: boolean + nextExport?: boolean } /** diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 1be45905b609d..e532e818eb85a 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -97,7 +97,7 @@ export function patchFetch({ if ( // we don't consider autoNoCache to switch to dynamic during // revalidate although if it occurs during build we do - (!autoNoCache || !staticGenerationStore.isRevalidate) && + (!autoNoCache || staticGenerationStore.isPrerendering) && (typeof staticGenerationStore.revalidate === 'undefined' || (typeof revalidate === 'number' && revalidate < staticGenerationStore.revalidate))