@@ -17,14 +17,30 @@ function getDomain(languageCode: string): string {
1717 return subdomain + 'react.dev' ;
1818}
1919
20+ export function getPageUrls ( pathname : string ) : {
21+ canonicalUrl : string ;
22+ languages : Record < string , string > ;
23+ siteDomain : string ;
24+ } {
25+ const siteDomain = getDomain ( siteConfig . languageCode ) ;
26+ const canonicalUrl = `https://${ siteDomain } ${ pathname } ` ;
27+ const languages : Record < string , string > = {
28+ 'x-default' : canonicalUrl . replace ( siteDomain , getDomain ( 'en' ) ) ,
29+ } ;
30+ for ( const code of finishedTranslations ) {
31+ languages [ code ] = canonicalUrl . replace ( siteDomain , getDomain ( code ) ) ;
32+ }
33+ return { canonicalUrl, languages, siteDomain} ;
34+ }
35+
2036export function buildPageMetadata ( {
2137 data,
2238 pathname,
2339 section,
2440 routeTree,
2541 title : titleOverride ,
2642} : {
27- data : PageData ;
43+ data : Pick < PageData , 'meta' > ;
2844 pathname : string ;
2945 section : PageSection ;
3046 title ?: string ;
@@ -48,27 +64,23 @@ export function buildPageMetadata({
4864 ? 'React is the library for web and native user interfaces. Build user interfaces out of individual pieces called components written in JavaScript. React is designed to let you seamlessly combine components written by independent people, teams, and organizations.'
4965 : 'The library for web and native user interfaces' ;
5066
51- const siteDomain = getDomain ( siteConfig . languageCode ) ;
52- const canonicalUrl = `https://${ siteDomain } ${ pathname } ` ;
67+ const { canonicalUrl, languages, siteDomain} = getPageUrls ( pathname ) ;
5368 // OG images are generated per page at build time by
5469 // scripts/generateOgImages.mjs. Pages without a generated card
55- // (home, errors) fall back to the static section image.
70+ // (home, errors, 404, 500 ) fall back to the static section image.
5671 const ogImage =
57- isHomePage || ! title || pathname . startsWith ( '/errors' )
72+ isHomePage ||
73+ ! title ||
74+ pathname . startsWith ( '/errors' ) ||
75+ pathname === '/404' ||
76+ pathname === '/500'
5877 ? `https://${ siteDomain } /images/og-${
5978 section === 'unknown' ? 'unknown' : section
6079 } .png`
6180 : `https://${ siteDomain } /images/og/${ pathname
6281 . slice ( 1 )
6382 . replace ( / \/ / g, '-' ) } .png`;
6483
65- const languages : Record < string , string > = {
66- 'x-default' : canonicalUrl . replace ( siteDomain , getDomain ( 'en' ) ) ,
67- } ;
68- for ( const code of finishedTranslations ) {
69- languages [ code ] = canonicalUrl . replace ( siteDomain , getDomain ( code ) ) ;
70- }
71-
7284 // Match the Pages Router behavior: emit `algolia-search-order` on Learn
7385 // pages and Blog post pages (not the Blog index) so Algolia can preserve
7486 // the docs sidebar ordering in search results.
@@ -86,13 +98,17 @@ export function buildPageMetadata({
8698 return {
8799 title : pageTitle ,
88100 description : isHomePage ? description : undefined ,
89- alternates : {
90- canonical : canonicalUrl ,
91- languages,
92- } ,
101+ // Next serializes the root URL as its bare origin. The home page renders
102+ // these URL tags directly so its canonical URL keeps the trailing slash.
103+ alternates : isHomePage
104+ ? undefined
105+ : {
106+ canonical : canonicalUrl ,
107+ languages,
108+ } ,
93109 openGraph : {
94110 type : 'website' ,
95- url : canonicalUrl ,
111+ url : isHomePage ? undefined : canonicalUrl ,
96112 title : pageTitle ,
97113 description,
98114 images : [ { url : ogImage } ] ,
@@ -108,3 +124,11 @@ export function buildPageMetadata({
108124 other : Object . keys ( other ) . length > 0 ? other : undefined ,
109125 } ;
110126}
127+
128+ export function buildNotFoundMetadata ( ) : Metadata {
129+ return buildPageMetadata ( {
130+ data : { meta : { title : 'Not Found' } } ,
131+ pathname : '/404' ,
132+ section : 'unknown' ,
133+ } ) ;
134+ }
0 commit comments