From 1fc9c47f208e652bd61c829ed2f4f767d71809b1 Mon Sep 17 00:00:00 2001 From: Jacob Fletcher Date: Wed, 4 Dec 2024 17:01:09 -0500 Subject: [PATCH] feat(next): supports relative preview URLs (#9755) Similar to #9746. When deploying to Vercel, preview deployment URLs are dynamically generated. This breaks `admin.preview` within those deployments because there is no mechanism by which we can detect and set that URL within Payload. Although Vercel provides various environment variables at our disposal, they provide no concrete identifier for exactly which URL is being currently previewed (you can access the same deployment from a number of different URLs). The fix is to support relative `admin.preview` URLs, that way Payload can prepend the application's top-level domain dynamically at render-time in order to create a fully qualified URL. So when you visit a Vercel preview deployment, for example, that deployment's unique URL is used as the preview redirect, instead of the application's root/production domain. Note: this does not fix multi-tenancy single-domain setups, as those still require a static top-level domain for each tenant. --- docs/admin/collections.mdx | 2 ++ docs/live-preview/overview.mdx | 4 ++-- packages/next/src/routes/rest/collections/preview.ts | 5 +++++ test/live-preview/collections/Pages.ts | 1 + test/live-preview/collections/Posts.ts | 1 + test/live-preview/collections/SSR.ts | 1 + test/live-preview/collections/SSRAutosave.ts | 1 + test/versions/collections/Autosave.ts | 1 - test/versions/collections/CustomIDs.ts | 1 - test/versions/collections/Drafts.ts | 1 - test/versions/collections/DraftsWithMax.ts | 1 - test/versions/collections/Versions.ts | 1 - test/versions/globals/Autosave.ts | 3 --- test/versions/globals/DraftWithMax.ts | 1 - 14 files changed, 13 insertions(+), 11 deletions(-) diff --git a/docs/admin/collections.mdx b/docs/admin/collections.mdx index 00c7bedba2..612febe2c6 100644 --- a/docs/admin/collections.mdx +++ b/docs/admin/collections.mdx @@ -108,6 +108,8 @@ export const Posts: CollectionConfig = { } ``` +The `preview` property resolves to a string that points to your front-end application with additional URL parameters. This can be an absolute URL or a relative path. If you are using a relative path, Payload will prepend the application's origin onto it, creating a fully qualified URL. + The preview function receives two arguments: | Argument | Description | diff --git a/docs/live-preview/overview.mdx b/docs/live-preview/overview.mdx index 7900e0db80..ef59472bf0 100644 --- a/docs/live-preview/overview.mdx +++ b/docs/live-preview/overview.mdx @@ -52,9 +52,9 @@ _\* An asterisk denotes that a property is required._ ### URL -The `url` property is a string that points to your front-end application. This value is used as the `src` attribute of the iframe rendering your front-end. Once loaded, the Admin Panel will communicate directly with your app through `window.postMessage` events. +The `url` property resolves to a string that points to your front-end application. This value is used as the `src` attribute of the iframe rendering your front-end. Once loaded, the Admin Panel will communicate directly with your app through `window.postMessage` events. -This can be an absolute URL or a relative path. If you are using a relative path, Payload will resolve it relative to the application's origin URL. This is useful for Vercel preview deployments, for example, where URLs are not known ahead of time. +This can be an absolute URL or a relative path. If you are using a relative path, Payload will prepend the application's origin onto it, creating a fully qualified URL. This is useful for Vercel preview deployments, for example, where URLs are not known ahead of time. To set the URL, use the `admin.livePreview.url` property in your [Payload Config](../configuration/overview): diff --git a/packages/next/src/routes/rest/collections/preview.ts b/packages/next/src/routes/rest/collections/preview.ts index 780eaa75f5..db4513d559 100644 --- a/packages/next/src/routes/rest/collections/preview.ts +++ b/packages/next/src/routes/rest/collections/preview.ts @@ -34,6 +34,11 @@ export const preview: CollectionRouteHandlerWithID = async ({ id, collection, re req, token, }) + + // Support relative URLs by prepending the origin, if necessary + if (previewURL && previewURL.startsWith('/')) { + previewURL = `${req.protocol}//${req.host}${previewURL}` + } } catch (err) { return routeError({ collection, diff --git a/test/live-preview/collections/Pages.ts b/test/live-preview/collections/Pages.ts index abd2ab725c..125039a69c 100644 --- a/test/live-preview/collections/Pages.ts +++ b/test/live-preview/collections/Pages.ts @@ -32,6 +32,7 @@ export const Pages: CollectionConfig = { }, }, }, + preview: (doc) => `/live-preview/${doc?.slug}`, }, fields: [ { diff --git a/test/live-preview/collections/Posts.ts b/test/live-preview/collections/Posts.ts index 60f22bd84e..cafc51598f 100644 --- a/test/live-preview/collections/Posts.ts +++ b/test/live-preview/collections/Posts.ts @@ -18,6 +18,7 @@ export const Posts: CollectionConfig = { admin: { useAsTitle: 'title', defaultColumns: ['id', 'title', 'slug', 'createdAt'], + preview: (doc) => `/live-preview/posts/${doc?.slug}`, }, fields: [ { diff --git a/test/live-preview/collections/SSR.ts b/test/live-preview/collections/SSR.ts index 69150b88d9..8d8c2bf732 100644 --- a/test/live-preview/collections/SSR.ts +++ b/test/live-preview/collections/SSR.ts @@ -22,6 +22,7 @@ export const SSR: CollectionConfig = { admin: { useAsTitle: 'title', defaultColumns: ['id', 'title', 'slug', 'createdAt'], + preview: (doc) => `/live-preview/ssr/${doc?.slug}`, }, fields: [ { diff --git a/test/live-preview/collections/SSRAutosave.ts b/test/live-preview/collections/SSRAutosave.ts index ef720bd64a..a19236c541 100644 --- a/test/live-preview/collections/SSRAutosave.ts +++ b/test/live-preview/collections/SSRAutosave.ts @@ -29,6 +29,7 @@ export const SSRAutosave: CollectionConfig = { admin: { useAsTitle: 'title', defaultColumns: ['id', 'title', 'slug', 'createdAt'], + preview: (doc) => `/live-preview/ssr-autosave/${doc?.slug}`, }, fields: [ { diff --git a/test/versions/collections/Autosave.ts b/test/versions/collections/Autosave.ts index 1c3d11f74e..3caaee13c2 100644 --- a/test/versions/collections/Autosave.ts +++ b/test/versions/collections/Autosave.ts @@ -11,7 +11,6 @@ const AutosavePosts: CollectionConfig = { admin: { useAsTitle: 'title', defaultColumns: ['title', 'description', 'createdAt', '_status'], - preview: () => 'https://payloadcms.com', }, versions: { maxPerDoc: 35, diff --git a/test/versions/collections/CustomIDs.ts b/test/versions/collections/CustomIDs.ts index 1176f6a365..fdb20dfc45 100644 --- a/test/versions/collections/CustomIDs.ts +++ b/test/versions/collections/CustomIDs.ts @@ -6,7 +6,6 @@ const CustomIDs: CollectionConfig = { slug: customIDSlug, admin: { defaultColumns: ['id', 'title', 'createdAt'], - preview: () => 'https://payloadcms.com', useAsTitle: 'id', }, fields: [ diff --git a/test/versions/collections/Drafts.ts b/test/versions/collections/Drafts.ts index 9ee974b3e7..b7c3426a66 100644 --- a/test/versions/collections/Drafts.ts +++ b/test/versions/collections/Drafts.ts @@ -44,7 +44,6 @@ const DraftPosts: CollectionConfig = { }, }, defaultColumns: ['title', 'description', 'createdAt', '_status'], - preview: () => 'https://payloadcms.com', useAsTitle: 'title', }, fields: [ diff --git a/test/versions/collections/DraftsWithMax.ts b/test/versions/collections/DraftsWithMax.ts index 0fbc861e8a..13d2e762bb 100644 --- a/test/versions/collections/DraftsWithMax.ts +++ b/test/versions/collections/DraftsWithMax.ts @@ -44,7 +44,6 @@ const DraftWithMaxPosts: CollectionConfig = { }, }, defaultColumns: ['title', 'description', 'createdAt', '_status'], - preview: () => 'https://payloadcms.com', useAsTitle: 'title', }, fields: [ diff --git a/test/versions/collections/Versions.ts b/test/versions/collections/Versions.ts index e5827c3d75..cdcbf8835a 100644 --- a/test/versions/collections/Versions.ts +++ b/test/versions/collections/Versions.ts @@ -29,7 +29,6 @@ const VersionPosts: CollectionConfig = { }, admin: { defaultColumns: ['title', 'description', 'createdAt'], - preview: () => 'https://payloadcms.com', useAsTitle: 'title', }, fields: [ diff --git a/test/versions/globals/Autosave.ts b/test/versions/globals/Autosave.ts index 434962477f..6b6d7fbe9a 100644 --- a/test/versions/globals/Autosave.ts +++ b/test/versions/globals/Autosave.ts @@ -26,9 +26,6 @@ const AutosaveGlobal: GlobalConfig = { } }, }, - admin: { - preview: () => 'https://payloadcms.com', - }, fields: [ { name: 'title', diff --git a/test/versions/globals/DraftWithMax.ts b/test/versions/globals/DraftWithMax.ts index 6a056d5bbf..dab8ec339f 100644 --- a/test/versions/globals/DraftWithMax.ts +++ b/test/versions/globals/DraftWithMax.ts @@ -6,7 +6,6 @@ const DraftWithMaxGlobal: GlobalConfig = { slug: draftWithMaxGlobalSlug, label: 'Draft Global', admin: { - preview: () => 'https://payloadcms.com', components: { views: { edit: {