Skip to content

Commit

Permalink
fix(resolve-metadata): allow for search params in canonical URL (#65366)
Browse files Browse the repository at this point in the history
When `alternates.canonical` is provided as a `URL` instance,
`searchParams` are discarded.
When canonical is provided as a string, the same search parameters work.
This behavior may be unintuitive.

#### Unexpected result (`foo=bar` is removed):
```ts
export const generateMetadata = () => {
	const canonical = new URL(`https://example.com/test?foo=bar`);

	return {
		alternates: { canonical: canonical },
	};
};
```

#### Works as expected:
```ts
export const generateMetadata = () => {
	const canonical = new URL(`https://example.com/test?foo=bar`);

	return {
		alternates: { canonical: canonical.toString() },
	};
};
```

Co-authored-by: Shu Ding <g@shud.in>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
  • Loading branch information
3 people committed May 13, 2024
1 parent 359fdb2 commit e2f579e
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 1 deletion.
78 changes: 78 additions & 0 deletions packages/next/src/lib/metadata/resolve-metadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,84 @@ describe('accumulateMetadata', () => {
})
})

it('should support string alternate canonical with search params', async () => {
const metadataItems: MetadataItems = [
[
{
alternates: {
canonical: 'https://localhost:3000/test?foo=bar',
languages: {
'en-US': 'https://example.com/en-US',
'de-DE': 'https://example.com/de-DE',
},
media: {
'only screen and (max-width: 600px)': '/mobile',
},
types: {
'application/rss+xml': 'https://example.com/rss',
},
},
},
null,
],
]
const metadata = await accumulateMetadata(metadataItems)
expect(metadata).toMatchObject({
alternates: {
canonical: { url: 'https://localhost:3000/test?foo=bar' },
languages: {
'en-US': [{ url: 'https://example.com/en-US' }],
'de-DE': [{ url: 'https://example.com/de-DE' }],
},
media: {
'only screen and (max-width: 600px)': [{ url: '/mobile' }],
},
types: {
'application/rss+xml': [{ url: 'https://example.com/rss' }],
},
},
})
})

it('should support URL alternate canonical with search params', async () => {
const metadataItems: MetadataItems = [
[
{
alternates: {
canonical: new URL('https://localhost:3000/test?foo=bar'),
languages: {
'en-US': 'https://example.com/en-US',
'de-DE': 'https://example.com/de-DE',
},
media: {
'only screen and (max-width: 600px)': '/mobile',
},
types: {
'application/rss+xml': 'https://example.com/rss',
},
},
},
null,
],
]
const metadata = await accumulateMetadata(metadataItems)
expect(metadata).toMatchObject({
alternates: {
canonical: { url: 'https://localhost:3000/test?foo=bar' },
languages: {
'en-US': [{ url: 'https://example.com/en-US' }],
'de-DE': [{ url: 'https://example.com/de-DE' }],
},
media: {
'only screen and (max-width: 600px)': [{ url: '/mobile' }],
},
types: {
'application/rss+xml': [{ url: 'https://example.com/rss' }],
},
},
})
})

it('should support alternate descriptors', async () => {
const metadataItems: MetadataItems = [
[
Expand Down
6 changes: 5 additions & 1 deletion packages/next/src/lib/metadata/resolvers/resolve-basics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ function resolveAlternateUrl(
// If alter native url is an URL instance,
// we treat it as a URL base and resolve with current pathname
if (url instanceof URL) {
url = new URL(metadataContext.pathname, url)
const newUrl = new URL(metadataContext.pathname, url)
url.searchParams.forEach((value, key) =>
newUrl.searchParams.set(key, value)
)
url = newUrl
}
return resolveAbsoluteUrlWithPathname(url, metadataBase, metadataContext)
}
Expand Down

0 comments on commit e2f579e

Please sign in to comment.