Skip to content

Commit 9728a35

Browse files
kshehadehhuozhi
andcommitted
Prevent append of trailing slash in cases where path ends with a file extension (#66636)
### What Skip adding trailing slash for file pattern like same origin urls ### Why Fixes #66635 Next.js will not append trailing slash for file like pattern urls when `trailingSlash` is enabled. This PR aligns the behavior of the metadata trailing slash appending with next-server route handling. --------- Co-authored-by: Jiachi Liu <[email protected]>
1 parent 44661c2 commit 9728a35

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

packages/next/src/lib/metadata/resolvers/resolve-url.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,17 @@ describe('resolveAbsoluteUrlWithPathname', () => {
108108
'https://example.com/foo?bar'
109109
)
110110
})
111+
112+
it('should not add trailing slash to relative url that matches file pattern', () => {
113+
expect(resolver('/foo.html')).toBe('https://example.com/foo.html')
114+
expect(resolver('/foo.html?q=v')).toBe('https://example.com/foo.html?q=v')
115+
expect(resolver(new URL('/.well-known/bar.jpg', metadataBase))).toBe(
116+
'https://example.com/.well-known/bar.jpg/'
117+
)
118+
expect(resolver(new URL('/foo.html', metadataBase))).toBe(
119+
'https://example.com/foo.html'
120+
)
121+
})
111122
})
112123
})
113124

packages/next/src/lib/metadata/resolvers/resolve-url.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ function resolveRelativeUrl(url: string | URL, pathname: string): string | URL {
8686
return url
8787
}
8888

89+
// The regex is matching logic from packages/next/src/lib/load-custom-routes.ts
90+
const FILE_REGEX =
91+
/^(?:\/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+))(\/?|$)/i
92+
function isFilePattern(pathname: string): boolean {
93+
return FILE_REGEX.test(pathname)
94+
}
95+
8996
// Resolve `pathname` if `url` is a relative path the compose with `metadataBase`.
9097
function resolveAbsoluteUrlWithPathname(
9198
url: string | URL,
@@ -110,18 +117,27 @@ function resolveAbsoluteUrlWithPathname(
110117
// - Doesn't have query
111118
if (trailingSlash && !resolvedUrl.endsWith('/')) {
112119
let isRelative = resolvedUrl.startsWith('/')
113-
let isExternal = false
114120
let hasQuery = resolvedUrl.includes('?')
121+
let isExternal = false
122+
let isFileUrl = false
123+
115124
if (!isRelative) {
116125
try {
117126
const parsedUrl = new URL(resolvedUrl)
118127
isExternal =
119128
metadataBase != null && parsedUrl.origin !== metadataBase.origin
129+
isFileUrl = isFilePattern(parsedUrl.pathname)
120130
} catch {
121131
// If it's not a valid URL, treat it as external
122132
isExternal = true
123133
}
124-
if (!isExternal && !hasQuery) return `${resolvedUrl}/`
134+
if (
135+
// Do not apply trailing slash for file like urls, aligning with the behavior with `trailingSlash`
136+
!isFileUrl &&
137+
!isExternal &&
138+
!hasQuery
139+
)
140+
return `${resolvedUrl}/`
125141
}
126142
}
127143

0 commit comments

Comments
 (0)