Skip to content

Commit 471cd1b

Browse files
authored
fix(next): properly construct local req url (#14907)
Fixes #14900. Supersedes #14901. Since #14869, loading the admin panel with a `serverURL` crashes with the following error: ``` ⨯ [TypeError: Invalid URL] { code: 'ERR_INVALID_URL', input: 'http://localhost:3000http://localhost:3000/admin', digest: '185251315' } [12:26:08] ERROR: Failed to create URL object from URL: http://localhost:3000http://localhost:3000/admin, falling back to http://localhost:3000http://localhost:3000/admin ``` This is because the suffix used to create a local req object was changed to include the server URL. As the name implies, it should be a relative path that appends onto the base URL.
1 parent 77f96a4 commit 471cd1b

File tree

11 files changed

+4824
-2
lines changed

11 files changed

+4824
-2
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ jobs:
326326
- plugin-redirects
327327
- plugin-seo
328328
- sort
329+
- server-url
329330
- trash
330331
- versions
331332
- uploads

packages/next/src/views/NotFound/index.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const NotFoundPage = async ({
4848

4949
const searchParams = await searchParamsPromise
5050
const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}`
51+
5152
const {
5253
locale,
5354
permissions,
@@ -65,7 +66,8 @@ export const NotFoundPage = async ({
6566
ignoreQueryPrefix: true,
6667
}),
6768
},
68-
urlSuffix: `${formatAdminURL({ adminRoute, path: '/not-found', serverURL: config.serverURL })}${searchParams ? queryString : ''}`,
69+
// intentionally omit `serverURL` to keep URL relative
70+
urlSuffix: `${formatAdminURL({ adminRoute, path: '/not-found' })}${searchParams ? queryString : ''}`,
6971
},
7072
})
7173

packages/next/src/views/Root/index.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export const RootPage = async ({
120120
}
121121

122122
const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}`
123+
123124
const {
124125
cookies,
125126
locale,
@@ -138,7 +139,11 @@ export const RootPage = async ({
138139
ignoreQueryPrefix: true,
139140
}),
140141
},
141-
urlSuffix: `${currentRoute}${searchParams ? queryString : ''}`,
142+
// intentionally omit `serverURL` to keep URL relative
143+
urlSuffix: `${formatAdminURL({
144+
adminRoute,
145+
path: Array.isArray(params.segments) ? `/${params.segments.join('/')}` : null,
146+
})}${searchParams ? queryString : ''}`,
142147
},
143148
})
144149

test/server-url/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/media
2+
/media-gif

test/server-url/config.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { lexicalEditor } from '@payloadcms/richtext-lexical'
2+
import { fileURLToPath } from 'node:url'
3+
import path from 'path'
4+
5+
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
6+
import { devUser } from '../credentials.js'
7+
8+
const filename = fileURLToPath(import.meta.url)
9+
const dirname = path.dirname(filename)
10+
11+
export default buildConfigWithDefaults({
12+
serverURL: 'http://localhost:3000',
13+
admin: {
14+
importMap: {
15+
baseDir: path.resolve(dirname),
16+
},
17+
},
18+
editor: lexicalEditor({}),
19+
onInit: async (payload) => {
20+
await payload.create({
21+
collection: 'users',
22+
data: {
23+
email: devUser.email,
24+
password: devUser.password,
25+
},
26+
})
27+
},
28+
typescript: {
29+
outputFile: path.resolve(dirname, 'payload-types.ts'),
30+
},
31+
})

test/server-url/e2e.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { Page } from '@playwright/test'
2+
3+
import { expect, test } from '@playwright/test'
4+
import * as path from 'path'
5+
import { fileURLToPath } from 'url'
6+
7+
import { ensureCompilationIsDone, initPageConsoleErrorCatch } from '../helpers.js'
8+
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
9+
import { initPayloadE2ENoConfig } from '../helpers/initPayloadE2ENoConfig.js'
10+
import { TEST_TIMEOUT_LONG } from '../playwright.config.js'
11+
12+
const filename = fileURLToPath(import.meta.url)
13+
const dirname = path.dirname(filename)
14+
15+
test.describe('serverURL', () => {
16+
let page: Page
17+
let url: AdminUrlUtil
18+
19+
test.beforeAll(async ({ browser }, testInfo) => {
20+
testInfo.setTimeout(TEST_TIMEOUT_LONG)
21+
22+
const { payload, serverURL } = await initPayloadE2ENoConfig({ dirname })
23+
url = new AdminUrlUtil(serverURL, 'posts')
24+
25+
const context = await browser.newContext()
26+
page = await context.newPage()
27+
initPageConsoleErrorCatch(page)
28+
await ensureCompilationIsDone({ page, serverURL })
29+
})
30+
31+
test('can load admin panel when serverURL is set', async () => {
32+
await page.goto(url.admin)
33+
await expect(page.getByText('Dashboard')).toBeVisible()
34+
})
35+
})

0 commit comments

Comments
 (0)