Fix noindex is missing on static not-found page (#67135)
### What Render noindex into a flight data and rsc payload when page path is `/404` ### Why 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.
This commit is contained in:
parent
16cf88e569
commit
fc7f62dc4e
5 changed files with 56 additions and 16 deletions
|
@ -298,6 +298,17 @@ function makeGetDynamicParamFromSegment(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function NonIndex({ ctx }: { ctx: AppRenderContext }) {
|
||||||
|
const is404Page = ctx.pagePath === '/404'
|
||||||
|
const isInvalidStatusCode =
|
||||||
|
typeof ctx.res.statusCode === 'number' && ctx.res.statusCode > 400
|
||||||
|
|
||||||
|
if (is404Page || isInvalidStatusCode) {
|
||||||
|
return <meta name="robots" content="noindex" />
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
// Handle Flight render request. This is only used when client-side navigating. E.g. when you `router.push('/dashboard')` or `router.reload()`.
|
// Handle Flight render request. This is only used when client-side navigating. E.g. when you `router.push('/dashboard')` or `router.reload()`.
|
||||||
async function generateFlight(
|
async function generateFlight(
|
||||||
ctx: AppRenderContext,
|
ctx: AppRenderContext,
|
||||||
|
@ -344,8 +355,11 @@ async function generateFlight(
|
||||||
isFirst: true,
|
isFirst: true,
|
||||||
// For flight, render metadata inside leaf page
|
// For flight, render metadata inside leaf page
|
||||||
rscPayloadHead: (
|
rscPayloadHead: (
|
||||||
// Adding requestId as react key to make metadata remount for each render
|
<>
|
||||||
|
<NonIndex ctx={ctx} />
|
||||||
|
{/* Adding requestId as react key to make metadata remount for each render */}
|
||||||
<MetadataTree key={requestId} />
|
<MetadataTree key={requestId} />
|
||||||
|
</>
|
||||||
),
|
),
|
||||||
injectedCSS: new Set(),
|
injectedCSS: new Set(),
|
||||||
injectedJS: new Set(),
|
injectedJS: new Set(),
|
||||||
|
@ -493,10 +507,7 @@ async function ReactServerApp({ tree, ctx, asNotFound }: ReactServerAppProps) {
|
||||||
couldBeIntercepted={couldBeIntercepted}
|
couldBeIntercepted={couldBeIntercepted}
|
||||||
initialHead={
|
initialHead={
|
||||||
<>
|
<>
|
||||||
{typeof ctx.res.statusCode === 'number' &&
|
<NonIndex ctx={ctx} />
|
||||||
ctx.res.statusCode > 400 && (
|
|
||||||
<meta name="robots" content="noindex" />
|
|
||||||
)}
|
|
||||||
{/* Adding requestId as react key to make metadata remount for each render */}
|
{/* Adding requestId as react key to make metadata remount for each render */}
|
||||||
<MetadataTree key={ctx.requestId} />
|
<MetadataTree key={ctx.requestId} />
|
||||||
</>
|
</>
|
||||||
|
@ -532,7 +543,6 @@ async function ReactServerError({
|
||||||
},
|
},
|
||||||
requestStore: { url },
|
requestStore: { url },
|
||||||
requestId,
|
requestId,
|
||||||
res,
|
|
||||||
} = ctx
|
} = ctx
|
||||||
|
|
||||||
const [MetadataTree] = createMetadataComponents({
|
const [MetadataTree] = createMetadataComponents({
|
||||||
|
@ -547,11 +557,9 @@ async function ReactServerError({
|
||||||
|
|
||||||
const head = (
|
const head = (
|
||||||
<>
|
<>
|
||||||
|
<NonIndex ctx={ctx} />
|
||||||
{/* Adding requestId as react key to make metadata remount for each render */}
|
{/* Adding requestId as react key to make metadata remount for each render */}
|
||||||
<MetadataTree key={requestId} />
|
<MetadataTree key={requestId} />
|
||||||
{typeof res.statusCode === 'number' && res.statusCode >= 400 && (
|
|
||||||
<meta name="robots" content="noindex" />
|
|
||||||
)}
|
|
||||||
{process.env.NODE_ENV === 'development' && (
|
{process.env.NODE_ENV === 'development' && (
|
||||||
<meta name="next-error" content="not-found" />
|
<meta name="next-error" content="not-found" />
|
||||||
)}
|
)}
|
||||||
|
@ -1269,7 +1277,7 @@ async function renderToHTMLOrFlightImpl(
|
||||||
setHeader('Location', redirectUrl)
|
setHeader('Location', redirectUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
const is404 = res.statusCode === 404
|
const is404 = ctx.res.statusCode === 404
|
||||||
if (!is404 && !hasRedirectError && !shouldBailoutToCSR) {
|
if (!is404 && !hasRedirectError && !shouldBailoutToCSR) {
|
||||||
res.statusCode = 500
|
res.statusCode = 500
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,6 @@
|
||||||
"app dir - metadata react cache should have same title and page value when navigating"
|
"app dir - metadata react cache should have same title and page value when navigating"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"test/e2e/app-dir/metadata-navigation/metadata-navigation.test.ts": {
|
|
||||||
"failed": [
|
|
||||||
"app dir - metadata navigation navigation should render root not-found with default metadata"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"test/e2e/middleware-rewrites/test/index.test.ts": {
|
"test/e2e/middleware-rewrites/test/index.test.ts": {
|
||||||
"failed": ["Middleware Rewrite should handle catch-all rewrite correctly"]
|
"failed": ["Middleware Rewrite should handle catch-all rewrite correctly"]
|
||||||
}
|
}
|
||||||
|
|
3
test/e2e/app-dir/not-found/default/app/foo/page.js
Normal file
3
test/e2e/app-dir/not-found/default/app/foo/page.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function Page() {
|
||||||
|
return <h1>Foo</h1>
|
||||||
|
}
|
7
test/e2e/app-dir/not-found/default/app/layout.js
Normal file
7
test/e2e/app-dir/not-found/default/app/layout.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export default function Layout({ children }) {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<body>{children}</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
}
|
27
test/e2e/app-dir/not-found/default/default.test.ts
Normal file
27
test/e2e/app-dir/not-found/default/default.test.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { nextTestSetup } from 'e2e-utils'
|
||||||
|
|
||||||
|
const isPPREnabled = process.env.__NEXT_EXPERIMENTAL_PPR === 'true'
|
||||||
|
|
||||||
|
describe('app dir - not-found - default', () => {
|
||||||
|
const { next, isNextStart } = nextTestSetup({
|
||||||
|
files: __dirname,
|
||||||
|
skipDeployment: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should has noindex in the head html', async () => {
|
||||||
|
const $ = await next.render$('/does-not-exist')
|
||||||
|
expect(await $('meta[name="robots"]').attr('content')).toBe('noindex')
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isNextStart) {
|
||||||
|
it('should contain noindex contain in the page', async () => {
|
||||||
|
const html = await next.readFile('.next/server/app/_not-found.html')
|
||||||
|
const rsc = await next.readFile(
|
||||||
|
`.next/server/app/_not-found.${isPPREnabled ? 'prefetch.' : ''}rsc`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(html).toContain('noindex')
|
||||||
|
expect(rsc).toContain('noindex')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in a new issue