Skip to content

Commit f0008d8

Browse files
committed
Fix noindex is missing on static not-found page (#67135)
Render noindex into a flight data and rsc payload when page path is `/404` When it's static generation, noindex is not rendered due to the statusCode from mock request is 200, but we can relying on the pagePath as `/404` page should always contain `nonidex` We were missing the noindex before for flight generation, now we'll render it when it's 404 page.
1 parent 3a6f211 commit f0008d8

File tree

4 files changed

+56
-8
lines changed

4 files changed

+56
-8
lines changed

packages/next/src/server/app-render/app-render.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,17 @@ function makeGetDynamicParamFromSegment(
259259
}
260260
}
261261

262+
function NonIndex({ ctx }: { ctx: AppRenderContext }) {
263+
const is404Page = ctx.pagePath === '/404'
264+
const isInvalidStatusCode =
265+
typeof ctx.res.statusCode === 'number' && ctx.res.statusCode > 400
266+
267+
if (is404Page || isInvalidStatusCode) {
268+
return <meta name="robots" content="noindex" />
269+
}
270+
return null
271+
}
272+
262273
// Handle Flight render request. This is only used when client-side navigating. E.g. when you `router.push('/dashboard')` or `router.reload()`.
263274
async function generateFlight(
264275
ctx: AppRenderContext,
@@ -306,8 +317,11 @@ async function generateFlight(
306317
isFirst: true,
307318
// For flight, render metadata inside leaf page
308319
rscPayloadHead: (
309-
// Adding requestId as react key to make metadata remount for each render
310-
<MetadataTree key={requestId} />
320+
<>
321+
<NonIndex ctx={ctx} />
322+
{/* Adding requestId as react key to make metadata remount for each render */}
323+
<MetadataTree key={requestId} />
324+
</>
311325
),
312326
injectedCSS: new Set(),
313327
injectedJS: new Set(),
@@ -457,9 +471,7 @@ async function ReactServerApp({ tree, ctx, asNotFound }: ReactServerAppProps) {
457471
couldBeIntercepted={couldBeIntercepted}
458472
initialHead={
459473
<>
460-
{ctx.res.statusCode > 400 && (
461-
<meta name="robots" content="noindex" />
462-
)}
474+
<NonIndex ctx={ctx} />
463475
{/* Adding requestId as react key to make metadata remount for each render */}
464476
<MetadataTree key={ctx.requestId} />
465477
</>
@@ -495,7 +507,6 @@ async function ReactServerError({
495507
},
496508
staticGenerationStore: { urlPathname },
497509
requestId,
498-
res,
499510
} = ctx
500511

501512
const [MetadataTree] = createMetadataComponents({
@@ -511,9 +522,9 @@ async function ReactServerError({
511522

512523
const head = (
513524
<>
525+
<NonIndex ctx={ctx} />
514526
{/* Adding requestId as react key to make metadata remount for each render */}
515527
<MetadataTree key={requestId} />
516-
{res.statusCode >= 400 && <meta name="robots" content="noindex" />}
517528
{process.env.NODE_ENV === 'development' && (
518529
<meta name="next-error" content="not-found" />
519530
)}
@@ -1200,7 +1211,7 @@ async function renderToHTMLOrFlightImpl(
12001211
res.setHeader('Location', redirectUrl)
12011212
}
12021213

1203-
const is404 = res.statusCode === 404
1214+
const is404 = ctx.res.statusCode === 404
12041215
if (!is404 && !hasRedirectError && !shouldBailoutToCSR) {
12051216
res.statusCode = 500
12061217
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Page() {
2+
return <h1>Foo</h1>
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Layout({ children }) {
2+
return (
3+
<html>
4+
<body>{children}</body>
5+
</html>
6+
)
7+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { nextTestSetup } from 'e2e-utils'
2+
3+
const isPPREnabled = process.env.__NEXT_EXPERIMENTAL_PPR === 'true'
4+
5+
describe('app dir - not-found - default', () => {
6+
const { next, isNextStart } = nextTestSetup({
7+
files: __dirname,
8+
skipDeployment: true,
9+
})
10+
11+
it('should has noindex in the head html', async () => {
12+
const $ = await next.render$('/does-not-exist')
13+
expect(await $('meta[name="robots"]').attr('content')).toBe('noindex')
14+
})
15+
16+
if (isNextStart) {
17+
it('should contain noindex contain in the page', async () => {
18+
const html = await next.readFile('.next/server/app/_not-found.html')
19+
const rsc = await next.readFile(
20+
`.next/server/app/_not-found.${isPPREnabled ? 'prefetch.' : ''}rsc`
21+
)
22+
23+
expect(html).toContain('noindex')
24+
expect(rsc).toContain('noindex')
25+
})
26+
}
27+
})

0 commit comments

Comments
 (0)