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.
This commit is contained in:
Jacob Fletcher
2024-12-04 17:01:09 -05:00
committed by GitHub
parent 61a4656ef5
commit 1fc9c47f20
14 changed files with 13 additions and 11 deletions

View File

@@ -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: The preview function receives two arguments:
| Argument | Description | | Argument | Description |

View File

@@ -52,9 +52,9 @@ _\* An asterisk denotes that a property is required._
### URL ### 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): To set the URL, use the `admin.livePreview.url` property in your [Payload Config](../configuration/overview):

View File

@@ -34,6 +34,11 @@ export const preview: CollectionRouteHandlerWithID = async ({ id, collection, re
req, req,
token, token,
}) })
// Support relative URLs by prepending the origin, if necessary
if (previewURL && previewURL.startsWith('/')) {
previewURL = `${req.protocol}//${req.host}${previewURL}`
}
} catch (err) { } catch (err) {
return routeError({ return routeError({
collection, collection,

View File

@@ -32,6 +32,7 @@ export const Pages: CollectionConfig = {
}, },
}, },
}, },
preview: (doc) => `/live-preview/${doc?.slug}`,
}, },
fields: [ fields: [
{ {

View File

@@ -18,6 +18,7 @@ export const Posts: CollectionConfig = {
admin: { admin: {
useAsTitle: 'title', useAsTitle: 'title',
defaultColumns: ['id', 'title', 'slug', 'createdAt'], defaultColumns: ['id', 'title', 'slug', 'createdAt'],
preview: (doc) => `/live-preview/posts/${doc?.slug}`,
}, },
fields: [ fields: [
{ {

View File

@@ -22,6 +22,7 @@ export const SSR: CollectionConfig = {
admin: { admin: {
useAsTitle: 'title', useAsTitle: 'title',
defaultColumns: ['id', 'title', 'slug', 'createdAt'], defaultColumns: ['id', 'title', 'slug', 'createdAt'],
preview: (doc) => `/live-preview/ssr/${doc?.slug}`,
}, },
fields: [ fields: [
{ {

View File

@@ -29,6 +29,7 @@ export const SSRAutosave: CollectionConfig = {
admin: { admin: {
useAsTitle: 'title', useAsTitle: 'title',
defaultColumns: ['id', 'title', 'slug', 'createdAt'], defaultColumns: ['id', 'title', 'slug', 'createdAt'],
preview: (doc) => `/live-preview/ssr-autosave/${doc?.slug}`,
}, },
fields: [ fields: [
{ {

View File

@@ -11,7 +11,6 @@ const AutosavePosts: CollectionConfig = {
admin: { admin: {
useAsTitle: 'title', useAsTitle: 'title',
defaultColumns: ['title', 'description', 'createdAt', '_status'], defaultColumns: ['title', 'description', 'createdAt', '_status'],
preview: () => 'https://payloadcms.com',
}, },
versions: { versions: {
maxPerDoc: 35, maxPerDoc: 35,

View File

@@ -6,7 +6,6 @@ const CustomIDs: CollectionConfig = {
slug: customIDSlug, slug: customIDSlug,
admin: { admin: {
defaultColumns: ['id', 'title', 'createdAt'], defaultColumns: ['id', 'title', 'createdAt'],
preview: () => 'https://payloadcms.com',
useAsTitle: 'id', useAsTitle: 'id',
}, },
fields: [ fields: [

View File

@@ -44,7 +44,6 @@ const DraftPosts: CollectionConfig = {
}, },
}, },
defaultColumns: ['title', 'description', 'createdAt', '_status'], defaultColumns: ['title', 'description', 'createdAt', '_status'],
preview: () => 'https://payloadcms.com',
useAsTitle: 'title', useAsTitle: 'title',
}, },
fields: [ fields: [

View File

@@ -44,7 +44,6 @@ const DraftWithMaxPosts: CollectionConfig = {
}, },
}, },
defaultColumns: ['title', 'description', 'createdAt', '_status'], defaultColumns: ['title', 'description', 'createdAt', '_status'],
preview: () => 'https://payloadcms.com',
useAsTitle: 'title', useAsTitle: 'title',
}, },
fields: [ fields: [

View File

@@ -29,7 +29,6 @@ const VersionPosts: CollectionConfig = {
}, },
admin: { admin: {
defaultColumns: ['title', 'description', 'createdAt'], defaultColumns: ['title', 'description', 'createdAt'],
preview: () => 'https://payloadcms.com',
useAsTitle: 'title', useAsTitle: 'title',
}, },
fields: [ fields: [

View File

@@ -26,9 +26,6 @@ const AutosaveGlobal: GlobalConfig = {
} }
}, },
}, },
admin: {
preview: () => 'https://payloadcms.com',
},
fields: [ fields: [
{ {
name: 'title', name: 'title',

View File

@@ -6,7 +6,6 @@ const DraftWithMaxGlobal: GlobalConfig = {
slug: draftWithMaxGlobalSlug, slug: draftWithMaxGlobalSlug,
label: 'Draft Global', label: 'Draft Global',
admin: { admin: {
preview: () => 'https://payloadcms.com',
components: { components: {
views: { views: {
edit: { edit: {