Skip to content

Commit

Permalink
Respect non 200 status to page static generation response (#63731)
Browse files Browse the repository at this point in the history
### What

In static generation phase of app page, if there's any case that we're
receiving 3xx/4xx status code from the response, we 're setting it into
the static generation meta now to make sure they're still returning the
same status after build.

### Why

During static generation if there's any 3xx/4xx status code that is set
in the response, we should respect to it, such as the ones caused by
using `notFound()` to mark as 404 response or `redirect` to mark as
`307` response.

Closes NEXT-2895
Fixes #51021
Fixes #62228
  • Loading branch information
huozhi committed Mar 27, 2024
1 parent 98e6fc5 commit 93aac0e
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 4 deletions.
19 changes: 15 additions & 4 deletions packages/next/src/export/routes/app-page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,23 @@ export async function exportAppPage(
'utf8'
)

const isParallelRoute = /\/@\w+/.test(page)
const isNonSuccessfulStatusCode = res.statusCode > 300
// When PPR is enabled, we don't always send 200 for routes that have been
// pregenerated, so we should grab the status code from the mocked
// response.
let status: number | undefined = renderOpts.experimental.ppr
? res.statusCode
: undefined

// If it's parallel route the status from mock response is 404
if (isNonSuccessfulStatusCode && !isParallelRoute) {
status = res.statusCode
}

// Writing the request metadata to a file.
const meta: RouteMetadata = {
// When PPR is enabled, we don't always send 200 for routes that have been
// pregenerated, so we should grab the status code from the mocked
// response.
status: renderOpts.experimental.ppr ? res.statusCode : undefined,
status,
headers,
postponed,
}
Expand Down
7 changes: 7 additions & 0 deletions test/e2e/app-dir/static-generation-status/app/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Layout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { notFound } from 'next/navigation'

export default function Page() {
notFound()
}

export const dynamic = 'force-static'
3 changes: 3 additions & 0 deletions test/e2e/app-dir/static-generation-status/app/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return 'home'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { redirect } from 'next/navigation'

export default function Page() {
redirect('/')
}

export const dynamic = 'force-static'
25 changes: 25 additions & 0 deletions test/e2e/app-dir/static-generation-status/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { createNextDescribe } from 'e2e-utils'

createNextDescribe(
'app-dir static-generation-status',
{
files: __dirname,
},
({ next }) => {
it('should render the page using notFound with status 404', async () => {
const { status } = await next.fetch('/not-found-page')
expect(status).toBe(404)
})

it('should render the page using redirect with status 307', async () => {
const { status } = await next.fetch('/redirect-page', {
redirect: 'manual',
})
expect(status).toBe(307)
})

it('should render the non existed route redirect with status 404', async () => {
expect((await next.fetch('/does-not-exist')).status).toBe(404)
})
}
)
7 changes: 7 additions & 0 deletions test/production/app-dir/parallel-routes-static/app/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return '@bar'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Default() {
return '@foo default'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function Layout({ children, bar, foo }) {
return (
<div>
<h1>Layout</h1>
<div id="foo-slot">{foo}</div>
<div id="bar-slot">{bar}</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <div>Hello from Nested</div>
}
26 changes: 26 additions & 0 deletions test/production/app-dir/parallel-routes-static/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createNextDescribe } from 'e2e-utils'

createNextDescribe(
'app-dir parallel-routes-static',
{
files: __dirname,
},
({ next }) => {
it('should static generate parallel routes', async () => {
const rscExtension = process.env.__NEXT_EXPERIMENTAL_PPR
? '.prefetch.rsc'
: '.rsc'
expect(await next.hasFile('.next/server/app/nested/foo.html')).toBe(true)
expect(await next.hasFile('.next/server/app/nested/foo.meta')).toBe(true)
expect(
await next.hasFile(`.next/server/app/nested/foo${rscExtension}`)
).toBe(true)

expect(await next.hasFile('.next/server/app/nested/bar.html')).toBe(true)
expect(await next.hasFile('.next/server/app/nested/bar.meta')).toBe(true)
expect(
await next.hasFile(`.next/server/app/nested/bar${rscExtension}`)
).toBe(true)
})
}
)

0 comments on commit 93aac0e

Please sign in to comment.