Skip to content

Commit a6946b6

Browse files
authored
Backport metadata fixes (#62663)
Backport metadata fixes #61898 #62109 #62615 Closes NEXT-2641
1 parent 4002f4b commit a6946b6

File tree

30 files changed

+249
-93
lines changed

30 files changed

+249
-93
lines changed

Diff for: packages/next/src/build/webpack/loaders/next-app-loader.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@ async function createAppRouteCode({
124124

125125
resolvedPagePath = `next-metadata-route-loader?${stringify({
126126
page,
127+
filePath: resolvedPagePath,
127128
isDynamic: isDynamic ? '1' : '0',
128-
})}!${resolvedPagePath}${`?${WEBPACK_RESOURCE_QUERIES.metadataRoute}`}`
129+
})}!?${WEBPACK_RESOURCE_QUERIES.metadataRoute}`
129130
}
130131

131132
const pathname = new AppPathnameNormalizer().normalize(page)

Diff for: packages/next/src/build/webpack/loaders/next-metadata-route-loader.ts

+12-9
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const cacheHeader = {
2222

2323
type MetadataRouteLoaderOptions = {
2424
page: string
25+
filePath: string
2526
isDynamic: '1' | '0'
2627
}
2728

@@ -46,7 +47,6 @@ function getContentType(resourcePath: string) {
4647
return 'text/plain'
4748
}
4849

49-
// Strip metadata resource query string from `import.meta.url` to make sure the fs.readFileSync get the right path.
5050
async function getStaticAssetRouteCode(
5151
resourcePath: string,
5252
fileBaseName: string
@@ -58,6 +58,7 @@ async function getStaticAssetRouteCode(
5858
? cacheHeader.none
5959
: cacheHeader.longCache
6060
const code = `\
61+
/* static asset route */
6162
import { NextResponse } from 'next/server'
6263
6364
const contentType = ${JSON.stringify(getContentType(resourcePath))}
@@ -82,6 +83,7 @@ export const dynamic = 'force-static'
8283

8384
function getDynamicTextRouteCode(resourcePath: string) {
8485
return `\
86+
/* dynamic asset route */
8587
import { NextResponse } from 'next/server'
8688
import handler from ${JSON.stringify(resourcePath)}
8789
import { resolveRouteData } from 'next/dist/build/webpack/loaders/metadata/resolve-route-data'
@@ -108,6 +110,7 @@ export async function GET() {
108110
// <metadata-image>/[id]/route.js
109111
function getDynamicImageRouteCode(resourcePath: string) {
110112
return `\
113+
/* dynamic image route */
111114
import { NextResponse } from 'next/server'
112115
import * as userland from ${JSON.stringify(resourcePath)}
113116
@@ -159,6 +162,7 @@ async function getDynamicSiteMapRouteCode(
159162
page.includes('[__metadata_id__]')
160163
) {
161164
staticGenerationCode = `\
165+
/* dynamic sitemap route */
162166
export async function generateStaticParams() {
163167
const sitemaps = generateSitemaps ? await generateSitemaps() : []
164168
const params = []
@@ -224,26 +228,25 @@ ${staticGenerationCode}
224228
`
225229
return code
226230
}
227-
// `import.meta.url` is the resource name of the current module.
231+
228232
// When it's static route, it could be favicon.ico, sitemap.xml, robots.txt etc.
229233
// TODO-METADATA: improve the cache control strategy
230234
const nextMetadataRouterLoader: webpack.LoaderDefinitionFunction<MetadataRouteLoaderOptions> =
231235
async function () {
232-
const { resourcePath } = this
233-
const { page, isDynamic } = this.getOptions()
234-
const { name: fileBaseName } = getFilenameAndExtension(resourcePath)
236+
const { page, isDynamic, filePath } = this.getOptions()
237+
const { name: fileBaseName } = getFilenameAndExtension(filePath)
235238

236239
let code = ''
237240
if (isDynamic === '1') {
238241
if (fileBaseName === 'robots' || fileBaseName === 'manifest') {
239-
code = getDynamicTextRouteCode(resourcePath)
242+
code = getDynamicTextRouteCode(filePath)
240243
} else if (fileBaseName === 'sitemap') {
241-
code = await getDynamicSiteMapRouteCode(resourcePath, page, this)
244+
code = await getDynamicSiteMapRouteCode(filePath, page, this)
242245
} else {
243-
code = getDynamicImageRouteCode(resourcePath)
246+
code = getDynamicImageRouteCode(filePath)
244247
}
245248
} else {
246-
code = await getStaticAssetRouteCode(resourcePath, fileBaseName)
249+
code = await getStaticAssetRouteCode(filePath, fileBaseName)
247250
}
248251

249252
return code

Diff for: packages/next/src/export/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ export async function exportAppImpl(
474474
distDir,
475475
dev: false,
476476
basePath: nextConfig.basePath,
477+
trailingSlash: nextConfig.trailingSlash,
477478
canonicalBase: nextConfig.amp?.canonicalBase || '',
478479
ampSkipValidation: nextConfig.experimental.amp?.skipValidation || false,
479480
ampOptimizerConfig: nextConfig.experimental.amp?.optimizer || undefined,

Diff for: packages/next/src/lib/metadata/metadata.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,22 @@ export function createMetadataComponents({
3939
tree,
4040
pathname,
4141
searchParams,
42+
trailingSlash,
4243
getDynamicParamFromSegment,
4344
appUsingSizeAdjustment,
4445
errorType,
4546
}: {
4647
tree: LoaderTree
4748
pathname: string
4849
searchParams: { [key: string]: any }
50+
trailingSlash: boolean
4951
getDynamicParamFromSegment: GetDynamicParamFromSegment
5052
appUsingSizeAdjustment: boolean
5153
errorType?: 'not-found' | 'redirect'
5254
}): [React.ComponentType, React.ComponentType] {
5355
const metadataContext = {
5456
pathname,
57+
trailingSlash,
5558
}
5659

5760
let resolve: (value: Error | undefined) => void | undefined

Diff for: packages/next/src/lib/metadata/resolve-metadata.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ function accumulateMetadata(metadataItems: MetadataItems) {
1616
])
1717
return originAccumulateMetadata(fullMetadataItems, {
1818
pathname: '/test',
19+
trailingSlash: false,
1920
})
2021
}
2122

Diff for: packages/next/src/lib/metadata/resolvers/resolve-basics.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ import type {
22
AlternateLinkDescriptor,
33
ResolvedAlternateURLs,
44
} from '../types/alternative-urls-types'
5-
import type { Metadata, ResolvedMetadata } from '../types/metadata-interface'
5+
import type {
6+
Metadata,
7+
ResolvedMetadata,
8+
Viewport,
9+
} from '../types/metadata-interface'
610
import type { ResolvedVerification } from '../types/metadata-types'
711
import type {
812
FieldResolver,
@@ -15,19 +19,21 @@ import { resolveAbsoluteUrlWithPathname } from './resolve-url'
1519
function resolveAlternateUrl(
1620
url: string | URL,
1721
metadataBase: URL | null,
18-
pathname: string
22+
metadataContext: MetadataContext
1923
) {
2024
// If alter native url is an URL instance,
2125
// we treat it as a URL base and resolve with current pathname
2226
if (url instanceof URL) {
23-
url = new URL(pathname, url)
27+
url = new URL(metadataContext.pathname, url)
2428
}
25-
return resolveAbsoluteUrlWithPathname(url, metadataBase, pathname)
29+
return resolveAbsoluteUrlWithPathname(url, metadataBase, metadataContext)
2630
}
2731

28-
export const resolveThemeColor: FieldResolver<'themeColor'> = (themeColor) => {
32+
export const resolveThemeColor: FieldResolver<'themeColor', Viewport> = (
33+
themeColor
34+
) => {
2935
if (!themeColor) return null
30-
const themeColorDescriptors: ResolvedMetadata['themeColor'] = []
36+
const themeColorDescriptors: Viewport['themeColor'] = []
3137

3238
resolveAsArrayOrUndefined(themeColor)?.forEach((descriptor) => {
3339
if (typeof descriptor === 'string')
@@ -51,7 +57,7 @@ function resolveUrlValuesOfObject(
5157
| null
5258
| undefined,
5359
metadataBase: ResolvedMetadata['metadataBase'],
54-
pathname: string
60+
metadataContext: MetadataContext
5561
): null | Record<string, AlternateLinkDescriptor[]> {
5662
if (!obj) return null
5763

@@ -60,13 +66,13 @@ function resolveUrlValuesOfObject(
6066
if (typeof value === 'string' || value instanceof URL) {
6167
result[key] = [
6268
{
63-
url: resolveAlternateUrl(value, metadataBase, pathname),
69+
url: resolveAlternateUrl(value, metadataBase, metadataContext),
6470
},
6571
]
6672
} else {
6773
result[key] = []
6874
value?.forEach((item, index) => {
69-
const url = resolveAlternateUrl(item.url, metadataBase, pathname)
75+
const url = resolveAlternateUrl(item.url, metadataBase, metadataContext)
7076
result[key][index] = {
7177
url,
7278
title: item.title,
@@ -80,7 +86,7 @@ function resolveUrlValuesOfObject(
8086
function resolveCanonicalUrl(
8187
urlOrDescriptor: string | URL | null | AlternateLinkDescriptor | undefined,
8288
metadataBase: URL | null,
83-
pathname: string
89+
metadataContext: MetadataContext
8490
): null | AlternateLinkDescriptor {
8591
if (!urlOrDescriptor) return null
8692

@@ -91,35 +97,35 @@ function resolveCanonicalUrl(
9197

9298
// Return string url because structureClone can't handle URL instance
9399
return {
94-
url: resolveAlternateUrl(url, metadataBase, pathname),
100+
url: resolveAlternateUrl(url, metadataBase, metadataContext),
95101
}
96102
}
97103

98104
export const resolveAlternates: FieldResolverExtraArgs<
99105
'alternates',
100106
[ResolvedMetadata['metadataBase'], MetadataContext]
101-
> = (alternates, metadataBase, { pathname }) => {
107+
> = (alternates, metadataBase, context) => {
102108
if (!alternates) return null
103109

104110
const canonical = resolveCanonicalUrl(
105111
alternates.canonical,
106112
metadataBase,
107-
pathname
113+
context
108114
)
109115
const languages = resolveUrlValuesOfObject(
110116
alternates.languages,
111117
metadataBase,
112-
pathname
118+
context
113119
)
114120
const media = resolveUrlValuesOfObject(
115121
alternates.media,
116122
metadataBase,
117-
pathname
123+
context
118124
)
119125
const types = resolveUrlValuesOfObject(
120126
alternates.types,
121127
metadataBase,
122-
pathname
128+
context
123129
)
124130

125131
const result: ResolvedAlternateURLs = {
@@ -236,12 +242,12 @@ export const resolveAppLinks: FieldResolver<'appLinks'> = (appLinks) => {
236242
export const resolveItunes: FieldResolverExtraArgs<
237243
'itunes',
238244
[ResolvedMetadata['metadataBase'], MetadataContext]
239-
> = (itunes, metadataBase, { pathname }) => {
245+
> = (itunes, metadataBase, context) => {
240246
if (!itunes) return null
241247
return {
242248
appId: itunes.appId,
243249
appArgument: itunes.appArgument
244-
? resolveAlternateUrl(itunes.appArgument, metadataBase, pathname)
250+
? resolveAlternateUrl(itunes.appArgument, metadataBase, context)
245251
: undefined,
246252
}
247253
}

0 commit comments

Comments
 (0)