From 0600293b034b7bfedbaef3bc6044979bc3119bab Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 11 Jul 2023 23:39:50 -0700 Subject: [PATCH] Fix ISR case with bot requests (#52581) This ensures we don't bail from static generation unexpectedly due to a bot request as this shouldn't affect ISR handling. Test deployment with patch can be seen here https://test-app-isr-fallback-dwn2neok6-vtest314-ijjk-testing.vercel.app/new Fixes: https://github.com/vercel/next.js/issues/47805 --- ...static-generation-async-storage-wrapper.ts | 4 +- .../required-server-files-app.test.ts | 55 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) 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 1e8653798f9c6..663dd6dc10601 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 @@ -53,9 +53,7 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper< * coalescing, and ISR continue working as intended. */ const isStaticGeneration = - !renderOpts.supportsDynamicHTML && - !renderOpts.isBot && - !renderOpts.isDraftMode + !renderOpts.supportsDynamicHTML && !renderOpts.isDraftMode const store: StaticGenerationStore = { isStaticGeneration, diff --git a/test/production/standalone-mode/required-server-files/required-server-files-app.test.ts b/test/production/standalone-mode/required-server-files/required-server-files-app.test.ts index 5da467ce703c6..869c5ea405ab0 100644 --- a/test/production/standalone-mode/required-server-files/required-server-files-app.test.ts +++ b/test/production/standalone-mode/required-server-files/required-server-files-app.test.ts @@ -1,6 +1,7 @@ import glob from 'glob' import fs from 'fs-extra' import { join } from 'path' +import cheerio from 'cheerio' import { createNext, FileRef } from 'e2e-utils' import { NextInstance } from 'test/lib/next-modes/base' import { @@ -99,6 +100,60 @@ describe('should set-up next', () => { expect(next.cliOutput).not.toContain('ERR_INVALID_URL') }) + it('should properly handle prerender for bot request', async () => { + const res = await fetchViaHTTP(appPort, '/isr/first', undefined, { + headers: { + 'user-agent': + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.179 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', + 'x-matched-path': '/isr/first', + }, + }) + + expect(res.status).toBe(200) + const html = await res.text() + const $ = cheerio.load(html) + + expect($('#page').text()).toBe('/isr/[slug]') + + const rscRes = await fetchViaHTTP(appPort, '/isr/first.rsc', undefined, { + headers: { + 'user-agent': + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.179 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', + 'x-matched-path': '/isr/first', + }, + }) + + expect(rscRes.status).toBe(200) + }) + + it('should properly handle fallback for bot request', async () => { + const res = await fetchViaHTTP(appPort, '/isr/[slug]', undefined, { + headers: { + 'user-agent': + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.179 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', + 'x-now-route-matches': '1=second&nxtPslug=new', + 'x-matched-path': '/isr/[slug]', + }, + }) + + expect(res.status).toBe(200) + const html = await res.text() + const $ = cheerio.load(html) + + expect($('#page').text()).toBe('/isr/[slug]') + + const rscRes = await fetchViaHTTP(appPort, '/isr/[slug].rsc', undefined, { + headers: { + 'user-agent': + 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.179 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)', + 'x-now-route-matches': '1=second&nxtPslug=new', + 'x-matched-path': '/isr/[slug]', + }, + }) + + expect(rscRes.status).toBe(200) + }) + it('should send cache tags in minimal mode for ISR', async () => { for (const [path, tags] of [ ['/isr/first', 'isr-page,/isr/[slug]/page'],