Ensure we don't poll page in development when notFound: true is returned (#34352)
Fixes: #34342 Visiting the following page will call gSSP indefinitely in a loop and logs errors from `on-demand-entries-client`: ```js const Home = () => null export default Home export function getServerSideProps() { console.log("gssp called") return { notFound: true } } ``` We should not keep fetching the page if it returns 404 as it can introduce unnecessary data requests. ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com>
This commit is contained in:
parent
7e93a89ba0
commit
9639fe704c
6 changed files with 53 additions and 1 deletions
|
@ -11,7 +11,17 @@ export default async (page) => {
|
|||
} else {
|
||||
Router.ready(() => {
|
||||
setInterval(() => {
|
||||
sendMessage(JSON.stringify({ event: 'ping', page: Router.pathname }))
|
||||
// when notFound: true is returned we should use the notFoundPage
|
||||
// as the Router.pathname will point to the 404 page but we want
|
||||
// to ping the source page that returned notFound: true instead
|
||||
const notFoundSrcPage = self.__NEXT_DATA__.notFoundSrcPage
|
||||
const pathname =
|
||||
(Router.pathname === '/404' || Router.pathname === '/_error') &&
|
||||
notFoundSrcPage
|
||||
? notFoundSrcPage
|
||||
: Router.pathname
|
||||
|
||||
sendMessage(JSON.stringify({ event: 'ping', page: pathname }))
|
||||
}, 2500)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1550,6 +1550,9 @@ export default abstract class Server {
|
|||
res.body('{"notFound":true}').send()
|
||||
return null
|
||||
} else {
|
||||
if (this.renderOpts.dev) {
|
||||
query.__nextNotFoundSrcPage = pathname
|
||||
}
|
||||
await this.render404(
|
||||
req,
|
||||
res,
|
||||
|
|
|
@ -528,9 +528,11 @@ export async function renderToHTML(
|
|||
const headTags = (...args: any) => callMiddleware('headTags', args)
|
||||
|
||||
const isFallback = !!query.__nextFallback
|
||||
const notFoundSrcPage = query.__nextNotFoundSrcPage
|
||||
delete query.__nextFallback
|
||||
delete query.__nextLocale
|
||||
delete query.__nextDefaultLocale
|
||||
delete query.__nextIsNotFound
|
||||
|
||||
const isSSG = !!getStaticProps
|
||||
const isBuildTimeSSG = isSSG && renderOpts.nextExport
|
||||
|
@ -1374,6 +1376,7 @@ export async function renderToHTML(
|
|||
defaultLocale,
|
||||
domainLocales,
|
||||
isPreview: isPreview === true ? true : undefined,
|
||||
notFoundSrcPage: notFoundSrcPage && dev ? notFoundSrcPage : undefined,
|
||||
},
|
||||
buildManifest: filteredBuildManifest,
|
||||
docComponentsRendered,
|
||||
|
|
|
@ -53,6 +53,7 @@ export function addRequestMeta<K extends keyof RequestMeta>(
|
|||
}
|
||||
|
||||
type NextQueryMetadata = {
|
||||
__nextNotFoundSrcPage?: string
|
||||
__nextDefaultLocale?: string
|
||||
__nextFallback?: 'true'
|
||||
__nextLocale?: string
|
||||
|
|
|
@ -107,6 +107,7 @@ export type NEXT_DATA = {
|
|||
domainLocales?: DomainLocale[]
|
||||
scriptLoader?: any[]
|
||||
isPreview?: boolean
|
||||
notFoundSrcPage?: string
|
||||
rsc?: boolean
|
||||
}
|
||||
|
||||
|
|
34
test/development/gssp-notfound/index.test.ts
Normal file
34
test/development/gssp-notfound/index.test.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { createNext } from 'e2e-utils'
|
||||
import { NextInstance } from 'test/lib/next-modes/base'
|
||||
import { waitFor } from 'next-test-utils'
|
||||
import webdriver from 'next-webdriver'
|
||||
|
||||
describe('getServerSideProps returns notFound: true', () => {
|
||||
let next: NextInstance
|
||||
|
||||
beforeAll(async () => {
|
||||
next = await createNext({
|
||||
files: {
|
||||
'pages/index.js': `
|
||||
const Home = () => null
|
||||
export default Home
|
||||
|
||||
export function getServerSideProps() {
|
||||
console.log("gssp called")
|
||||
return { notFound: true }
|
||||
}
|
||||
`,
|
||||
},
|
||||
dependencies: {},
|
||||
})
|
||||
})
|
||||
afterAll(() => next.destroy())
|
||||
|
||||
it('should not poll indefinitely', async () => {
|
||||
const browser = await webdriver(next.appPort, '/')
|
||||
await waitFor(3000)
|
||||
await browser.close()
|
||||
const logOccurrences = next.cliOutput.split('gssp called').length - 1
|
||||
expect(logOccurrences).toBe(1)
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue