Ensure getStaticProps is called for SSG 404 in blocking mode (#18300)
This ensures that when using a `pages/404` file with `getStaticProps` that we call `getStaticProps` in `fallback: 'blocking'` mode Fixes: https://github.com/vercel/next.js/issues/18293
This commit is contained in:
parent
f7ba546e8a
commit
0f25051470
3 changed files with 140 additions and 4 deletions
|
@ -492,7 +492,7 @@ const nextServerlessLoader: loader.Loader = function () {
|
|||
export async function renderReqToHTML(req, res, renderMode, _renderOpts, _params) {
|
||||
let Document
|
||||
let Error
|
||||
let NotFound
|
||||
let notFoundMod
|
||||
;[
|
||||
getStaticProps,
|
||||
getServerSideProps,
|
||||
|
@ -502,7 +502,7 @@ const nextServerlessLoader: loader.Loader = function () {
|
|||
config,
|
||||
{ default: Document },
|
||||
{ default: Error },
|
||||
${absolute404Path ? `{ default: NotFound }, ` : ''}
|
||||
${absolute404Path ? `notFoundMod, ` : ''}
|
||||
] = await Promise.all([
|
||||
getStaticProps,
|
||||
getServerSideProps,
|
||||
|
@ -772,13 +772,15 @@ const nextServerlessLoader: loader.Loader = function () {
|
|||
res.statusCode = 404
|
||||
|
||||
const NotFoundComponent = ${
|
||||
absolute404Path ? 'NotFound' : 'Error'
|
||||
absolute404Path ? 'notFoundMod.default' : 'Error'
|
||||
}
|
||||
|
||||
const errPathname = "${absolute404Path ? '/404' : '/_error'}"
|
||||
|
||||
const result = await renderToHTML(req, res, errPathname, parsedUrl.query, Object.assign({}, options, {
|
||||
getStaticProps: undefined,
|
||||
getStaticProps: ${
|
||||
absolute404Path ? `notFoundMod.getStaticProps` : 'undefined'
|
||||
},
|
||||
getStaticPaths: undefined,
|
||||
getServerSideProps: undefined,
|
||||
Component: NotFoundComponent,
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function Page(props) {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<>
|
||||
<p id="gsp">gsp page</p>
|
||||
<p id="props">{JSON.stringify(props)}</p>
|
||||
<p id="router-locale">{router.locale}</p>
|
||||
<p id="router-locales">{JSON.stringify(router.locales)}</p>
|
||||
<p id="router-query">{JSON.stringify(router.query)}</p>
|
||||
<p id="router-pathname">{router.pathname}</p>
|
||||
<p id="router-as-path">{router.asPath}</p>
|
||||
<Link href="/">
|
||||
<a id="to-index">to /</a>
|
||||
</Link>
|
||||
<br />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export const getStaticProps = ({ params, locale, locales }) => {
|
||||
if (locale === 'en' || locale === 'nl') {
|
||||
return {
|
||||
notFound: true,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
params,
|
||||
locale,
|
||||
locales,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const getStaticPaths = () => {
|
||||
return {
|
||||
// the default locale will be used since one isn't defined here
|
||||
paths: ['first', 'second'].map((slug) => ({
|
||||
params: { slug },
|
||||
})),
|
||||
fallback: 'blocking',
|
||||
}
|
||||
}
|
|
@ -106,6 +106,16 @@ function runTests(isDev) {
|
|||
initialRevalidateSeconds: false,
|
||||
srcRoute: '/gsp/no-fallback/[slug]',
|
||||
},
|
||||
'/en-US/not-found/blocking-fallback/first': {
|
||||
dataRoute: `/_next/data/${buildId}/en-US/not-found/blocking-fallback/first.json`,
|
||||
initialRevalidateSeconds: false,
|
||||
srcRoute: '/not-found/blocking-fallback/[slug]',
|
||||
},
|
||||
'/en-US/not-found/blocking-fallback/second': {
|
||||
dataRoute: `/_next/data/${buildId}/en-US/not-found/blocking-fallback/second.json`,
|
||||
initialRevalidateSeconds: false,
|
||||
srcRoute: '/not-found/blocking-fallback/[slug]',
|
||||
},
|
||||
'/en-US/not-found/fallback/first': {
|
||||
dataRoute: `/_next/data/${buildId}/en-US/not-found/fallback/first.json`,
|
||||
initialRevalidateSeconds: false,
|
||||
|
@ -157,6 +167,18 @@ function runTests(isDev) {
|
|||
)}/gsp/no\\-fallback/([^/]+?)\\.json$`
|
||||
),
|
||||
},
|
||||
'/not-found/blocking-fallback/[slug]': {
|
||||
dataRoute: `/_next/data/${buildId}/not-found/blocking-fallback/[slug].json`,
|
||||
dataRouteRegex: normalizeRegEx(
|
||||
`^\\/_next\\/data\\/${escapeRegex(
|
||||
buildId
|
||||
)}\\/not\\-found\\/blocking\\-fallback\\/([^\\/]+?)\\.json$`
|
||||
),
|
||||
fallback: null,
|
||||
routeRegex: normalizeRegEx(
|
||||
`^\\/not\\-found\\/blocking\\-fallback\\/([^\\/]+?)(?:\\/)?$`
|
||||
),
|
||||
},
|
||||
'/not-found/fallback/[slug]': {
|
||||
dataRoute: `/_next/data/${buildId}/not-found/fallback/[slug].json`,
|
||||
dataRouteRegex: normalizeRegEx(
|
||||
|
@ -957,6 +979,70 @@ function runTests(isDev) {
|
|||
expect(await browser.eval('window.beforeNav')).toBe(1)
|
||||
})
|
||||
|
||||
it('should render 404 for blocking fallback page that returned 404 on client transition', async () => {
|
||||
const browser = await webdriver(appPort, '/en', true, true)
|
||||
await browser.eval(`(function() {
|
||||
next.router.push('/not-found/blocking-fallback/first')
|
||||
})()`)
|
||||
await browser.waitForElementByCss('h1')
|
||||
await browser.eval('window.beforeNav = 1')
|
||||
|
||||
expect(await browser.elementByCss('html').text()).toContain(
|
||||
'This page could not be found'
|
||||
)
|
||||
const props = JSON.parse(await browser.elementByCss('#props').text())
|
||||
|
||||
expect(props.is404).toBe(true)
|
||||
expect(props.locale).toBe('en')
|
||||
expect(await browser.elementByCss('html').getAttribute('lang')).toBe('en')
|
||||
|
||||
const parsedUrl = url.parse(
|
||||
await browser.eval('window.location.href'),
|
||||
true
|
||||
)
|
||||
expect(parsedUrl.pathname).toBe('/en/not-found/blocking-fallback/first')
|
||||
expect(parsedUrl.query).toEqual({})
|
||||
|
||||
if (isDev) {
|
||||
// make sure page doesn't reload un-necessarily in development
|
||||
await waitFor(10 * 1000)
|
||||
}
|
||||
expect(await browser.eval('window.beforeNav')).toBe(1)
|
||||
})
|
||||
|
||||
it('should render 404 for blocking fallback page that returned 404', async () => {
|
||||
const browser = await webdriver(
|
||||
appPort,
|
||||
'/en/not-found/blocking-fallback/first',
|
||||
true,
|
||||
true
|
||||
)
|
||||
await browser.waitForElementByCss('h1')
|
||||
await browser.eval('window.beforeNav = 1')
|
||||
|
||||
expect(await browser.elementByCss('html').text()).toContain(
|
||||
'This page could not be found'
|
||||
)
|
||||
const props = JSON.parse(await browser.elementByCss('#props').text())
|
||||
|
||||
expect(props.is404).toBe(true)
|
||||
expect(props.locale).toBe('en')
|
||||
expect(await browser.elementByCss('html').getAttribute('lang')).toBe('en')
|
||||
|
||||
const parsedUrl = url.parse(
|
||||
await browser.eval('window.location.href'),
|
||||
true
|
||||
)
|
||||
expect(parsedUrl.pathname).toBe('/en/not-found/blocking-fallback/first')
|
||||
expect(parsedUrl.query).toEqual({})
|
||||
|
||||
if (isDev) {
|
||||
// make sure page doesn't reload un-necessarily in development
|
||||
await waitFor(10 * 1000)
|
||||
}
|
||||
expect(await browser.eval('window.beforeNav')).toBe(1)
|
||||
})
|
||||
|
||||
it('should not remove locale prefix for default locale', async () => {
|
||||
const res = await fetchViaHTTP(appPort, '/en-US', undefined, {
|
||||
redirect: 'manual',
|
||||
|
|
Loading…
Reference in a new issue