From 31b32ef94169547a36d26fac7005960ad128fb4b Mon Sep 17 00:00:00 2001 From: James Mikrut Date: Sat, 16 Nov 2024 15:30:05 -0500 Subject: [PATCH] feat: deprecates getPayloadHMR in favor of simpler getPayload (#9249) Deprecates `getPayloadHMR` and simplifies this pattern into a single `import { getPayload } from 'payload'`. We will still retain the exported `getPayloadHMR` but it now will throw a deprecation warning with instructions for how to migrate. --- docs/getting-started/concepts.mdx | 9 +- docs/live-preview/server.mdx | 4 +- docs/local-api/outside-nextjs.mdx | 5 +- docs/local-api/overview.mdx | 27 +--- examples/auth/payload/README.md | 4 +- .../payload/src/app/(app)/account/page.tsx | 4 +- .../src/app/(app)/create-account/page.tsx | 4 +- .../auth/payload/src/app/(app)/login/page.tsx | 6 +- .../payload/src/app/(app)/logout/page.tsx | 6 +- examples/auth/payload/src/app/(app)/page.tsx | 4 +- .../src/app/(app)/recover-password/page.tsx | 6 +- .../src/app/(app)/reset-password/page.tsx | 6 +- examples/live-preview/payload/README.md | 4 +- .../payload/src/app/(app)/[slug]/page.tsx | 17 +-- .../app/(app)/_components/Header/index.tsx | 4 +- .../src/app/(app)/[tenant]/[...slug]/page.tsx | 4 +- packages/next/package.json | 4 +- packages/next/src/exports/utilities.ts | 2 +- packages/next/src/layouts/Root/index.tsx | 5 +- packages/next/src/routes/rest/routeError.ts | 5 +- .../src/utilities/createPayloadRequest.ts | 11 +- packages/next/src/utilities/getPayloadHMR.ts | 139 +----------------- packages/next/src/utilities/initPage/index.ts | 5 +- packages/next/src/utilities/initReq.ts | 5 +- packages/payload/package.json | 4 +- packages/payload/src/index.ts | 117 ++++++++++++++- pnpm-lock.yaml | 12 +- .../src/app/(frontend)/[slug]/page.tsx | 6 +- .../src/app/(frontend)/next/preview/route.ts | 4 +- .../src/app/(frontend)/posts/[slug]/page.tsx | 6 +- .../website/src/app/(frontend)/posts/page.tsx | 4 +- .../posts/page/[pageNumber]/page.tsx | 6 +- .../src/app/(frontend)/search/page.tsx | 4 +- .../src/blocks/ArchiveBlock/Component.tsx | 4 +- .../website/src/utilities/getDocument.ts | 4 +- templates/website/src/utilities/getGlobals.ts | 4 +- .../website/src/utilities/getRedirects.ts | 4 +- .../src/app/(frontend)/[slug]/page.tsx | 6 +- .../src/app/(frontend)/next/preview/route.ts | 4 +- .../src/app/(frontend)/posts/[slug]/page.tsx | 6 +- .../src/app/(frontend)/posts/page.tsx | 4 +- .../posts/page/[pageNumber]/page.tsx | 6 +- .../src/app/(frontend)/search/page.tsx | 4 +- .../src/blocks/ArchiveBlock/Component.tsx | 4 +- .../src/utilities/getDocument.ts | 4 +- .../src/utilities/getGlobals.ts | 4 +- .../src/utilities/getRedirects.ts | 4 +- test/app/(app)/test/page.tsx | 4 +- test/fields/int.spec.ts | 3 +- test/helpers/initPayloadInt.ts | 6 +- .../app/live-preview/_api/getDoc.ts | 8 +- .../app/live-preview/_api/getDocs.ts | 4 +- .../app/live-preview/_api/getFooter.ts | 4 +- .../app/live-preview/_api/getHeader.ts | 4 +- .../prod/app/live-preview/_api/getDoc.ts | 8 +- .../prod/app/live-preview/_api/getDocs.ts | 4 +- .../prod/app/live-preview/_api/getFooter.ts | 4 +- .../prod/app/live-preview/_api/getHeader.ts | 4 +- 58 files changed, 264 insertions(+), 304 deletions(-) diff --git a/docs/getting-started/concepts.mdx b/docs/getting-started/concepts.mdx index d4fd1ceb23..71912ab73c 100644 --- a/docs/getting-started/concepts.mdx +++ b/docs/getting-started/concepts.mdx @@ -68,15 +68,10 @@ Here's a quick example of a React Server Component fetching data using the Local ```tsx import React from 'react' import config from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' const MyServerComponent: React.FC = () => { - // If you're working in Next.js, and you want HMR, - // you should get Payload via the `getPayloadHMR` function. - const payload = await getPayloadHMR({ config }) - - // If you are writing a standalone script and do not need HMR, - // you can get Payload via import { getPayload } from 'payload' instead. + const payload = await getPayload({ config }) // The `findResult` here will be fully typed as `PaginatedDocs`, // where you will have the `docs` that are returned as well as diff --git a/docs/live-preview/server.mdx b/docs/live-preview/server.mdx index 26e71b4bae..cbd945011b 100644 --- a/docs/live-preview/server.mdx +++ b/docs/live-preview/server.mdx @@ -34,11 +34,11 @@ Then, render the `RefreshRouteOnSave` component anywhere in your `page.tsx`. Her ```tsx import { RefreshRouteOnSave } from './RefreshRouteOnSave.tsx' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import config from '../payload.config' export default async function Page() { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const page = await payload.findByID({ collection: 'pages', diff --git a/docs/local-api/outside-nextjs.mdx b/docs/local-api/outside-nextjs.mdx index de24b5279c..020c0c3472 100644 --- a/docs/local-api/outside-nextjs.mdx +++ b/docs/local-api/outside-nextjs.mdx @@ -18,12 +18,9 @@ Payload can be used completely outside of Next.js which is helpful in cases like Payload provides a convenient way to run standalone scripts, which can be useful for tasks like seeding your database or performing one-off operations. -In standalone scripts, can simply import the Payload Config and use it right away. If you need an initialized copy of Payload, you can then use the `getPayload` function. This can be useful for tasks like seeding your database or performing other one-off operations. +In standalone scripts, you can simply import the Payload Config and use it right away. If you need an initialized copy of Payload, you can then use the `getPayload` function. This can be useful for tasks like seeding your database or performing other one-off operations. ```ts -// We are importing `getPayload` because we don't need HMR -// for a standalone script. For usage of Payload inside Next.js, -// you should always use `import { getPayloadHMR } from '@payloadcms/next/utilities'` instead. import { getPayload } from 'payload' import config from '@payload-config' diff --git a/docs/local-api/overview.mdx b/docs/local-api/overview.mdx index 5921465c4c..f0f713c102 100644 --- a/docs/local-api/overview.mdx +++ b/docs/local-api/overview.mdx @@ -43,27 +43,6 @@ const afterChangeHook: CollectionAfterChangeHook = async ({ req: { payload } }) If you want to import Payload in places where you don't have the option to access it from function arguments or `req`, you can import it and initialize it. -There are two places to import Payload: - -**Option 1 - using HMR, within Next.js** - -```ts -import { getPayloadHMR } from '@payloadcms/next/utilities' -import config from '@payload-config' - -const payload = await getPayloadHMR({ config }) -``` - -You should import Payload using the first option (`getPayloadHMR`) if you are using Payload inside of Next.js (like route handlers, server components, and similar.) - -This way, in Next.js development mode, Payload will work with Hot Module Replacement (HMR), and as you make changes to your Payload Config, your usage of Payload will always be in sync with your changes. In production, `getPayloadHMR` simply disables all HMR functionality so you don't need to write your code any differently. We handle optimization for you in production mode. - -If you are accessing Payload via function arguments or `req.payload`, HMR is automatically supported if you are using it within Next.js. - -**Option 2 - outside of Next.js** - -If you are using Payload outside of Next.js, for example in standalone scripts or in other frameworks, you can import Payload with no HMR functionality. Instead of using `getPayloadHMR`, you can use `getPayload`. - ```ts import { getPayload } from 'payload' import config from '@payload-config' @@ -71,7 +50,11 @@ import config from '@payload-config' const payload = await getPayload({ config }) ``` -Both options function in exactly the same way outside of one having HMR support and the other not. For more information about using Payload outside of Next.js, [click here](./outside-nextjs). +If you're working in Next.js' development mode, Payload will work with Hot Module Replacement (HMR), and as you make changes to your Payload Config, your usage of Payload will always be in sync with your changes. In production, `getPayload` simply disables all HMR functionality so you don't need to write your code any differently. We handle optimization for you in production mode. + +If you are accessing Payload via function arguments or `req.payload`, HMR is automatically supported if you are using it within Next.js. + +For more information about using Payload outside of Next.js, [click here](./outside-nextjs). ## Local options available diff --git a/examples/auth/payload/README.md b/examples/auth/payload/README.md index b4a74c9bfd..16bf667d58 100644 --- a/examples/auth/payload/README.md +++ b/examples/auth/payload/README.md @@ -48,12 +48,12 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc ```ts import { headers as getHeaders } from 'next/headers.js' - import { getPayloadHMR } from '@payloadcms/next/utilities' + import { getPayload } from 'payload' import config from '../../payload.config' export default async function AccountPage({ searchParams }) { const headers = getHeaders() - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const { permissions, user } = await payload.auth({ headers }) if (!user) { diff --git a/examples/auth/payload/src/app/(app)/account/page.tsx b/examples/auth/payload/src/app/(app)/account/page.tsx index 21aab2d1e6..fe6132b87b 100644 --- a/examples/auth/payload/src/app/(app)/account/page.tsx +++ b/examples/auth/payload/src/app/(app)/account/page.tsx @@ -1,7 +1,7 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import Link from 'next/link' import { redirect } from 'next/navigation' +import { getPayload } from 'payload' import React, { Fragment } from 'react' import config from '../../../payload.config' @@ -14,7 +14,7 @@ import classes from './index.module.scss' export default async function Account() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { permissions, user } = await payload.auth({ headers }) if (!user) { diff --git a/examples/auth/payload/src/app/(app)/create-account/page.tsx b/examples/auth/payload/src/app/(app)/create-account/page.tsx index cafe19da5b..cf27fa1906 100644 --- a/examples/auth/payload/src/app/(app)/create-account/page.tsx +++ b/examples/auth/payload/src/app/(app)/create-account/page.tsx @@ -1,6 +1,6 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import { redirect } from 'next/navigation' +import { getPayload } from 'payload' import React from 'react' import config from '../../../payload.config' @@ -11,7 +11,7 @@ import classes from './index.module.scss' export default async function CreateAccount() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { user } = await payload.auth({ headers }) if (user) { diff --git a/examples/auth/payload/src/app/(app)/login/page.tsx b/examples/auth/payload/src/app/(app)/login/page.tsx index 7f98d33094..9b183fa1ff 100644 --- a/examples/auth/payload/src/app/(app)/login/page.tsx +++ b/examples/auth/payload/src/app/(app)/login/page.tsx @@ -1,17 +1,17 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import { redirect } from 'next/navigation' +import { getPayload } from 'payload' import React from 'react' import config from '../../../payload.config' import { Gutter } from '../_components/Gutter' import { RenderParams } from '../_components/RenderParams' -import { LoginForm } from './LoginForm' import classes from './index.module.scss' +import { LoginForm } from './LoginForm' export default async function Login() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { user } = await payload.auth({ headers }) if (user) { diff --git a/examples/auth/payload/src/app/(app)/logout/page.tsx b/examples/auth/payload/src/app/(app)/logout/page.tsx index 13a8cab86d..f47c5aba01 100644 --- a/examples/auth/payload/src/app/(app)/logout/page.tsx +++ b/examples/auth/payload/src/app/(app)/logout/page.tsx @@ -1,16 +1,16 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import Link from 'next/link' +import { getPayload } from 'payload' import React from 'react' import config from '../../../payload.config' import { Gutter } from '../_components/Gutter' -import { LogoutPage } from './LogoutPage' import classes from './index.module.scss' +import { LogoutPage } from './LogoutPage' export default async function Logout() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { user } = await payload.auth({ headers }) if (!user) { diff --git a/examples/auth/payload/src/app/(app)/page.tsx b/examples/auth/payload/src/app/(app)/page.tsx index afd23fd1d4..c849be7419 100644 --- a/examples/auth/payload/src/app/(app)/page.tsx +++ b/examples/auth/payload/src/app/(app)/page.tsx @@ -1,6 +1,6 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import Link from 'next/link' +import { getPayload } from 'payload' import React, { Fragment } from 'react' import config from '../../payload.config' @@ -9,7 +9,7 @@ import { HydrateClientUser } from './_components/HydrateClientUser' export default async function HomePage() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { permissions, user } = await payload.auth({ headers }) return ( diff --git a/examples/auth/payload/src/app/(app)/recover-password/page.tsx b/examples/auth/payload/src/app/(app)/recover-password/page.tsx index 0750058ac9..fd6b56f0c8 100644 --- a/examples/auth/payload/src/app/(app)/recover-password/page.tsx +++ b/examples/auth/payload/src/app/(app)/recover-password/page.tsx @@ -1,16 +1,16 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import { redirect } from 'next/navigation' +import { getPayload } from 'payload' import React from 'react' import config from '../../../payload.config' import { Gutter } from '../_components/Gutter' -import { RecoverPasswordForm } from './RecoverPasswordForm' import classes from './index.module.scss' +import { RecoverPasswordForm } from './RecoverPasswordForm' export default async function RecoverPassword() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { user } = await payload.auth({ headers }) if (user) { diff --git a/examples/auth/payload/src/app/(app)/reset-password/page.tsx b/examples/auth/payload/src/app/(app)/reset-password/page.tsx index 56075e0f9e..ae170fe59f 100644 --- a/examples/auth/payload/src/app/(app)/reset-password/page.tsx +++ b/examples/auth/payload/src/app/(app)/reset-password/page.tsx @@ -1,16 +1,16 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers.js' import { redirect } from 'next/navigation' +import { getPayload } from 'payload' import React from 'react' import config from '../../../payload.config' import { Gutter } from '../_components/Gutter' -import { ResetPasswordForm } from './ResetPasswordForm' import classes from './index.module.scss' +import { ResetPasswordForm } from './ResetPasswordForm' export default async function ResetPassword() { const headers = getHeaders() - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { user } = await payload.auth({ headers }) if (user) { diff --git a/examples/live-preview/payload/README.md b/examples/live-preview/payload/README.md index ad8852505f..17c8c34131 100644 --- a/examples/live-preview/payload/README.md +++ b/examples/live-preview/payload/README.md @@ -107,11 +107,11 @@ Then, render `RefreshRouteOnSave` anywhere in your `page.tsx`. Here's an example ```tsx import { RefreshRouteOnSave } from './RefreshRouteOnSave.tsx' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import config from '../payload.config' export default async function Page() { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const page = await payload.find({ collection: 'pages', diff --git a/examples/live-preview/payload/src/app/(app)/[slug]/page.tsx b/examples/live-preview/payload/src/app/(app)/[slug]/page.tsx index 993368ea9e..2b4e0760ee 100644 --- a/examples/live-preview/payload/src/app/(app)/[slug]/page.tsx +++ b/examples/live-preview/payload/src/app/(app)/[slug]/page.tsx @@ -1,23 +1,22 @@ -/* eslint-disable no-restricted-exports */ -import { getPayloadHMR } from '@payloadcms/next/utilities' import { notFound } from 'next/navigation' -import React from 'react' -import { Fragment } from 'react' +/* eslint-disable no-restricted-exports */ +import { getPayload } from 'payload' +import React, { Fragment } from 'react' import type { Page as PageType } from '../../../payload-types' import config from '../../../payload.config' import { Gutter } from '../_components/Gutter' import RichText from '../_components/RichText' -import { RefreshRouteOnSave } from './RefreshRouteOnSave' import classes from './index.module.scss' +import { RefreshRouteOnSave } from './RefreshRouteOnSave' interface PageParams { params: { slug: string } } export default async function Page({ params: { slug = 'home' } }: PageParams) { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const pageRes = await payload.find({ collection: 'pages', @@ -30,7 +29,7 @@ export default async function Page({ params: { slug = 'home' } }: PageParams) { }, }) - const data = pageRes?.docs?.[0] as PageType | null + const data = pageRes?.docs?.[0] as null | PageType if (data === null) { return notFound() @@ -49,7 +48,7 @@ export default async function Page({ params: { slug = 'home' } }: PageParams) { } export async function generateStaticParams() { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const pagesRes = await payload.find({ collection: 'pages', @@ -66,5 +65,5 @@ export async function generateStaticParams() { slug, } : {}, - ) // eslint-disable-line function-paren-newline + ) } diff --git a/examples/live-preview/payload/src/app/(app)/_components/Header/index.tsx b/examples/live-preview/payload/src/app/(app)/_components/Header/index.tsx index 2b452a1b57..1fcf57c1b9 100644 --- a/examples/live-preview/payload/src/app/(app)/_components/Header/index.tsx +++ b/examples/live-preview/payload/src/app/(app)/_components/Header/index.tsx @@ -1,6 +1,6 @@ -import { getPayloadHMR } from '@payloadcms/next/utilities' import Image from 'next/image' import Link from 'next/link' +import { getPayload } from 'payload' import React from 'react' import config from '../../../../payload.config' @@ -9,7 +9,7 @@ import { Gutter } from '../Gutter' import classes from './index.module.scss' export const Header = async () => { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const mainMenu = await payload.findGlobal({ slug: 'main-menu', diff --git a/examples/multi-tenant/src/app/(app)/[tenant]/[...slug]/page.tsx b/examples/multi-tenant/src/app/(app)/[tenant]/[...slug]/page.tsx index 5fce8fb32a..05b6e3aa18 100644 --- a/examples/multi-tenant/src/app/(app)/[tenant]/[...slug]/page.tsx +++ b/examples/multi-tenant/src/app/(app)/[tenant]/[...slug]/page.tsx @@ -1,16 +1,16 @@ import type { Where } from 'payload' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' import { headers as getHeaders } from 'next/headers' import { notFound, redirect } from 'next/navigation' +import { getPayload } from 'payload' import React from 'react' import { RenderPage } from '../../../components/RenderPage' export default async function Page({ params }: { params: { slug?: string[]; tenant: string } }) { const headers = await getHeaders() - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const { user } = await payload.auth({ headers }) const tenantsQuery = await payload.find({ diff --git a/packages/next/package.json b/packages/next/package.json index 8be2b9e9f1..a184360d6f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -96,8 +96,7 @@ "react-diff-viewer-continued": "3.2.6", "sass": "1.77.4", "sonner": "^1.5.0", - "uuid": "10.0.0", - "ws": "^8.16.0" + "uuid": "10.0.0" }, "devDependencies": { "@babel/cli": "^7.24.5", @@ -111,7 +110,6 @@ "@types/react": "npm:types-react@19.0.0-rc.1", "@types/react-dom": "npm:types-react-dom@19.0.0-rc.1", "@types/uuid": "10.0.0", - "@types/ws": "^8.5.10", "babel-plugin-react-compiler": "0.0.0-experimental-24ec0eb-20240918", "esbuild": "0.23.1", "esbuild-sass-plugin": "3.3.1", diff --git a/packages/next/src/exports/utilities.ts b/packages/next/src/exports/utilities.ts index a51d6d5978..e384dc1853 100644 --- a/packages/next/src/exports/utilities.ts +++ b/packages/next/src/exports/utilities.ts @@ -3,6 +3,6 @@ export { addDataAndFileToRequest } from '../utilities/addDataAndFileToRequest.js export { addLocalesToRequestFromData, sanitizeLocales } from '../utilities/addLocalesToRequest.js' export { createPayloadRequest } from '../utilities/createPayloadRequest.js' export { getNextRequestI18n } from '../utilities/getNextRequestI18n.js' -export { getPayloadHMR, reload } from '../utilities/getPayloadHMR.js' +export { getPayloadHMR } from '../utilities/getPayloadHMR.js' export { headersWithCors } from '../utilities/headersWithCors.js' export { mergeHeaders } from '../utilities/mergeHeaders.js' diff --git a/packages/next/src/layouts/Root/index.tsx b/packages/next/src/layouts/Root/index.tsx index 7f494d17f1..6372f1bcfc 100644 --- a/packages/next/src/layouts/Root/index.tsx +++ b/packages/next/src/layouts/Root/index.tsx @@ -5,12 +5,11 @@ import { rtlLanguages } from '@payloadcms/translations' import { RootProvider } from '@payloadcms/ui' import '@payloadcms/ui/scss/app.scss' import { headers as getHeaders, cookies as nextCookies } from 'next/headers.js' -import { checkDependencies, parseCookies } from 'payload' +import { checkDependencies, getPayload, parseCookies } from 'payload' import React from 'react' import { getNavPrefs } from '../../elements/Nav/getNavPrefs.js' import { getClientConfig } from '../../utilities/getClientConfig.js' -import { getPayloadHMR } from '../../utilities/getPayloadHMR.js' import { getRequestLanguage } from '../../utilities/getRequestLanguage.js' import { getRequestTheme } from '../../utilities/getRequestTheme.js' import { initReq } from '../../utilities/initReq.js' @@ -100,7 +99,7 @@ export const RootLayout = async ({ headers, }) - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { i18n, permissions, req, user } = await initReq(config) diff --git a/packages/next/src/routes/rest/routeError.ts b/packages/next/src/routes/rest/routeError.ts index 1542eb9962..9fb05a4996 100644 --- a/packages/next/src/routes/rest/routeError.ts +++ b/packages/next/src/routes/rest/routeError.ts @@ -1,9 +1,8 @@ import type { Collection, ErrorResult, PayloadRequest, SanitizedConfig } from 'payload' import httpStatus from 'http-status' -import { APIError, formatErrors } from 'payload' +import { APIError, formatErrors, getPayload } from 'payload' -import { getPayloadHMR } from '../../utilities/getPayloadHMR.js' import { headersWithCors } from '../../utilities/headersWithCors.js' import { mergeHeaders } from '../../utilities/mergeHeaders.js' @@ -22,7 +21,7 @@ export const routeError = async ({ if (!payload) { try { - payload = await getPayloadHMR({ config: configArg }) + payload = await getPayload({ config: configArg }) } catch (e) { return Response.json( { diff --git a/packages/next/src/utilities/createPayloadRequest.ts b/packages/next/src/utilities/createPayloadRequest.ts index 2faa143f33..3ddeb3df0a 100644 --- a/packages/next/src/utilities/createPayloadRequest.ts +++ b/packages/next/src/utilities/createPayloadRequest.ts @@ -1,12 +1,17 @@ import type { CustomPayloadRequestProperties, PayloadRequest, SanitizedConfig } from 'payload' import { initI18n } from '@payloadcms/translations' -import { executeAuthStrategies, getDataLoader, parseCookies, sanitizeFallbackLocale } from 'payload' +import { + executeAuthStrategies, + getDataLoader, + getPayload, + parseCookies, + sanitizeFallbackLocale, +} from 'payload' import * as qs from 'qs-esm' import { URL } from 'url' import { sanitizeLocales } from './addLocalesToRequest.js' -import { getPayloadHMR } from './getPayloadHMR.js' import { getRequestLanguage } from './getRequestLanguage.js' type Args = { @@ -23,7 +28,7 @@ export const createPayloadRequest = async ({ request, }: Args): Promise => { const cookies = parseCookies(request.headers) - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const { config } = payload const localization = config.localization diff --git a/packages/next/src/utilities/getPayloadHMR.ts b/packages/next/src/utilities/getPayloadHMR.ts index b9789aa119..17c0eb4a7b 100644 --- a/packages/next/src/utilities/getPayloadHMR.ts +++ b/packages/next/src/utilities/getPayloadHMR.ts @@ -1,140 +1,15 @@ -import type { InitOptions, Payload, SanitizedConfig } from 'payload' +import type { InitOptions, Payload } from 'payload' -import { BasePayload, generateImportMap } from 'payload' -import WebSocket from 'ws' - -let cached: { - payload: null | Payload - promise: null | Promise - reload: boolean | Promise - ws: null | WebSocket -} = global._payload - -if (!cached) { - cached = global._payload = { payload: null, promise: null, reload: false, ws: null } -} - -export const reload = async ( - config: SanitizedConfig, - payload: Payload, - skipImportMapGeneration?: boolean, -): Promise => { - if (typeof payload.db.destroy === 'function') { - await payload.db.destroy() - } - - payload.config = config - - payload.collections = config.collections.reduce((collections, collection) => { - collections[collection.slug] = { - config: collection, - customIDType: payload.collections[collection.slug]?.customIDType, - } - return collections - }, {}) - - payload.globals = { - config: config.globals, - } - - // TODO: support HMR for other props in the future (see payload/src/index init()) hat may change on Payload singleton - - // Generate types - if (config.typescript.autoGenerate !== false) { - // We cannot run it directly here, as generate-types imports json-schema-to-typescript, which breaks on turbopack. - // see: https://github.com/vercel/next.js/issues/66723 - void payload.bin({ - args: ['generate:types'], - log: false, - }) - } - - // Generate component map - if (skipImportMapGeneration !== true && config.admin?.importMap?.autoGenerate !== false) { - await generateImportMap(config, { - log: true, - }) - } - - await payload.db.init() - if (payload.db.connect) { - await payload.db.connect({ hotReload: true }) - } -} +import { getPayload } from 'payload' export const getPayloadHMR = async ( options: Pick, ): Promise => { - if (!options?.config) { - throw new Error('Error: the payload config is required for getPayloadHMR to work.') - } + const result = await getPayload(options) - if (cached.payload) { - if (cached.reload === true) { - let resolve: () => void + result.logger.error( + "Deprecation warning: getPayloadHMR is no longer preferred. You can now use `import { getPayload } from 'payload' in all contexts.", + ) - // getPayloadHMR is called multiple times, in parallel. However, we only want to run `await reload` once. By immediately setting cached.reload to a promise, - // we can ensure that all subsequent calls will wait for the first reload to finish. So if we set it here, the 2nd call of getPayloadHMR - // will reach `if (cached.reload instanceof Promise) {` which then waits for the first reload to finish. - cached.reload = new Promise((res) => (resolve = res)) - const config = await options.config - await reload(config, cached.payload) - - resolve() - } - - if (cached.reload instanceof Promise) { - await cached.reload - } - - if (options?.importMap) { - cached.payload.importMap = options.importMap - } - return cached.payload - } - - // eslint-disable-next-line @typescript-eslint/no-misused-promises - if (!cached.promise) { - // no need to await options.config here, as it's already awaited in the BasePayload.init - cached.promise = new BasePayload().init(options) - } - - try { - cached.payload = await cached.promise - - if ( - !cached.ws && - process.env.NODE_ENV !== 'production' && - process.env.NODE_ENV !== 'test' && - process.env.DISABLE_PAYLOAD_HMR !== 'true' - ) { - try { - const port = process.env.PORT || '3000' - cached.ws = new WebSocket( - `ws://localhost:${port}${process.env.NEXT_BASE_PATH ?? ''}/_next/webpack-hmr`, - ) - - cached.ws.onmessage = (event) => { - if (typeof event.data === 'string') { - const data = JSON.parse(event.data) - - if ('action' in data && data.action === 'serverComponentChanges') { - cached.reload = true - } - } - } - } catch (_) { - // swallow e - } - } - } catch (e) { - cached.promise = null - throw e - } - - if (options?.importMap) { - cached.payload.importMap = options.importMap - } - - return cached.payload + return result } diff --git a/packages/next/src/utilities/initPage/index.ts b/packages/next/src/utilities/initPage/index.ts index 1daecbe0cd..55a335f313 100644 --- a/packages/next/src/utilities/initPage/index.ts +++ b/packages/next/src/utilities/initPage/index.ts @@ -4,12 +4,11 @@ import type { InitPageResult, Locale, VisibleEntities } from 'payload' import { findLocaleFromCode } from '@payloadcms/ui/shared' import { headers as getHeaders } from 'next/headers.js' import { notFound } from 'next/navigation.js' -import { createLocalReq, isEntityHidden, parseCookies } from 'payload' +import { createLocalReq, getPayload, isEntityHidden, parseCookies } from 'payload' import * as qs from 'qs-esm' import type { Args } from './types.js' -import { getPayloadHMR } from '../getPayloadHMR.js' import { initReq } from '../initReq.js' import { getRouteInfo } from './handleAdminPage.js' import { handleAuthRedirect } from './handleAuthRedirect.js' @@ -23,7 +22,7 @@ export const initPage = async ({ searchParams, }: Args): Promise => { const headers = await getHeaders() - const payload = await getPayloadHMR({ config: configPromise, importMap }) + const payload = await getPayload({ config: configPromise, importMap }) const queryString = `${qs.stringify(searchParams ?? {}, { addQueryPrefix: true })}` const { diff --git a/packages/next/src/utilities/initReq.ts b/packages/next/src/utilities/initReq.ts index c0a8f1c18b..6ac4c26725 100644 --- a/packages/next/src/utilities/initReq.ts +++ b/packages/next/src/utilities/initReq.ts @@ -3,10 +3,9 @@ import type { PayloadRequest, SanitizedConfig, SanitizedPermissions, User } from import { initI18n } from '@payloadcms/translations' import { headers as getHeaders } from 'next/headers.js' -import { createLocalReq, parseCookies } from 'payload' +import { createLocalReq, getPayload, parseCookies } from 'payload' import { cache } from 'react' -import { getPayloadHMR } from './getPayloadHMR.js' import { getRequestLanguage } from './getRequestLanguage.js' type Result = { @@ -20,7 +19,7 @@ export const initReq = cache(async function ( configPromise: Promise | SanitizedConfig, ): Promise { const config = await configPromise - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const headers = await getHeaders() const cookies = parseCookies(headers) diff --git a/packages/payload/package.json b/packages/payload/package.json index e13d0d77d6..37cc64821f 100644 --- a/packages/payload/package.json +++ b/packages/payload/package.json @@ -109,7 +109,8 @@ "scmp": "2.1.0", "ts-essentials": "10.0.3", "tsx": "4.19.2", - "uuid": "10.0.0" + "uuid": "10.0.0", + "ws": "^8.16.0" }, "devDependencies": { "@hyrious/esbuild-plugin-commonjs": "^0.2.4", @@ -120,6 +121,7 @@ "@types/pluralize": "0.0.33", "@types/react-datepicker": "6.2.0", "@types/uuid": "10.0.0", + "@types/ws": "^8.5.10", "copyfiles": "2.4.1", "cross-env": "7.0.3", "esbuild": "0.23.1", diff --git a/packages/payload/src/index.ts b/packages/payload/src/index.ts index 5841c15eb3..49fc380f25 100644 --- a/packages/payload/src/index.ts +++ b/packages/payload/src/index.ts @@ -6,6 +6,7 @@ import { spawn } from 'child_process' import crypto from 'crypto' import { fileURLToPath } from 'node:url' import path from 'path' +import WebSocket from 'ws' import type { AuthArgs } from './auth/operations/auth.js' import type { Result as ForgotPasswordResult } from './auth/operations/forgotPassword.js' @@ -17,7 +18,6 @@ import type { Options as VerifyEmailOptions } from './auth/operations/local/veri import type { Result as LoginResult } from './auth/operations/login.js' import type { Result as ResetPasswordResult } from './auth/operations/resetPassword.js' import type { AuthStrategy, User } from './auth/types.js' -import type { ImportMap } from './bin/generateImportMap/index.js' import type { BulkOperationResult, Collection, @@ -25,6 +25,8 @@ import type { SelectFromCollectionSlug, TypeWithID, } from './collections/config/types.js' + +import { generateImportMap, type ImportMap } from './bin/generateImportMap/index.js' export type { FieldState } from './admin/forms/Form.js' export type * from './admin/types.js' import type { NonNever } from 'ts-essentials' @@ -726,32 +728,139 @@ const initialized = new BasePayload() export default initialized -let cached = global._payload +let cached: { + payload: null | Payload + promise: null | Promise + reload: boolean | Promise + ws: null | WebSocket +} = global._payload if (!cached) { - cached = global._payload = { payload: null, promise: null } + cached = global._payload = { payload: null, promise: null, reload: false, ws: null } } -export const getPayload = async (options: InitOptions): Promise => { +export const reload = async ( + config: SanitizedConfig, + payload: Payload, + skipImportMapGeneration?: boolean, +): Promise => { + if (typeof payload.db.destroy === 'function') { + await payload.db.destroy() + } + + payload.config = config + + payload.collections = config.collections.reduce((collections, collection) => { + collections[collection.slug] = { + config: collection, + customIDType: payload.collections[collection.slug]?.customIDType, + } + return collections + }, {}) + + payload.globals = { + config: config.globals, + } + + // TODO: support HMR for other props in the future (see payload/src/index init()) that may change on Payload singleton + + // Generate types + if (config.typescript.autoGenerate !== false) { + // We cannot run it directly here, as generate-types imports json-schema-to-typescript, which breaks on turbopack. + // see: https://github.com/vercel/next.js/issues/66723 + void payload.bin({ + args: ['generate:types'], + log: false, + }) + } + + // Generate component map + if (skipImportMapGeneration !== true && config.admin?.importMap?.autoGenerate !== false) { + await generateImportMap(config, { + log: true, + }) + } + + await payload.db.init() + if (payload.db.connect) { + await payload.db.connect({ hotReload: true }) + } +} + +export const getPayload = async ( + options: Pick, +): Promise => { if (!options?.config) { throw new Error('Error: the payload config is required for getPayload to work.') } if (cached.payload) { + if (cached.reload === true) { + let resolve: () => void + + // getPayload is called multiple times, in parallel. However, we only want to run `await reload` once. By immediately setting cached.reload to a promise, + // we can ensure that all subsequent calls will wait for the first reload to finish. So if we set it here, the 2nd call of getPayload + // will reach `if (cached.reload instanceof Promise) {` which then waits for the first reload to finish. + cached.reload = new Promise((res) => (resolve = res)) + const config = await options.config + await reload(config, cached.payload) + + resolve() + } + + if (cached.reload instanceof Promise) { + await cached.reload + } + + if (options?.importMap) { + cached.payload.importMap = options.importMap + } return cached.payload } + // eslint-disable-next-line @typescript-eslint/no-misused-promises if (!cached.promise) { + // no need to await options.config here, as it's already awaited in the BasePayload.init cached.promise = new BasePayload().init(options) } try { cached.payload = await cached.promise + + if ( + !cached.ws && + process.env.NODE_ENV !== 'production' && + process.env.NODE_ENV !== 'test' && + process.env.DISABLE_PAYLOAD_HMR !== 'true' + ) { + try { + const port = process.env.PORT || '3000' + cached.ws = new WebSocket( + `ws://localhost:${port}${process.env.NEXT_BASE_PATH ?? ''}/_next/webpack-hmr`, + ) + + cached.ws.onmessage = (event) => { + if (typeof event.data === 'string') { + const data = JSON.parse(event.data) + + if ('action' in data && data.action === 'serverComponentChanges') { + cached.reload = true + } + } + } + } catch (_) { + // swallow e + } + } } catch (e) { cached.promise = null throw e } + if (options?.importMap) { + cached.payload.importMap = options.importMap + } + return cached.payload } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef5624e9ab..b105259690 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -739,9 +739,6 @@ importers: uuid: specifier: 10.0.0 version: 10.0.0 - ws: - specifier: ^8.16.0 - version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) devDependencies: '@babel/cli': specifier: ^7.24.5 @@ -776,9 +773,6 @@ importers: '@types/uuid': specifier: 10.0.0 version: 10.0.0 - '@types/ws': - specifier: ^8.5.10 - version: 8.5.13 babel-plugin-react-compiler: specifier: 0.0.0-experimental-24ec0eb-20240918 version: 0.0.0-experimental-24ec0eb-20240918 @@ -881,6 +875,9 @@ importers: uuid: specifier: 10.0.0 version: 10.0.0 + ws: + specifier: ^8.16.0 + version: 8.18.0(bufferutil@4.0.8)(utf-8-validate@6.0.5) devDependencies: '@hyrious/esbuild-plugin-commonjs': specifier: ^0.2.4 @@ -906,6 +903,9 @@ importers: '@types/uuid': specifier: 10.0.0 version: 10.0.0 + '@types/ws': + specifier: ^8.5.10 + version: 8.5.13 copyfiles: specifier: 2.4.1 version: 2.4.1 diff --git a/templates/website/src/app/(frontend)/[slug]/page.tsx b/templates/website/src/app/(frontend)/[slug]/page.tsx index 926f91ce8e..8cf49b88e3 100644 --- a/templates/website/src/app/(frontend)/[slug]/page.tsx +++ b/templates/website/src/app/(frontend)/[slug]/page.tsx @@ -2,7 +2,7 @@ import type { Metadata } from 'next' import { PayloadRedirects } from '@/components/PayloadRedirects' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { draftMode } from 'next/headers' import React, { cache } from 'react' import { homeStatic } from '@/endpoints/seed/home-static' @@ -15,7 +15,7 @@ import { generateMeta } from '@/utilities/generateMeta' import PageClient from './page.client' export async function generateStaticParams() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const pages = await payload.find({ collection: 'pages', draft: false, @@ -85,7 +85,7 @@ export async function generateMetadata({ params: paramsPromise }): Promise { const { isEnabled: draft } = await draftMode() - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const result = await payload.find({ collection: 'pages', diff --git a/templates/website/src/app/(frontend)/next/preview/route.ts b/templates/website/src/app/(frontend)/next/preview/route.ts index a68ef127ff..e6bcf65c2a 100644 --- a/templates/website/src/app/(frontend)/next/preview/route.ts +++ b/templates/website/src/app/(frontend)/next/preview/route.ts @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken' import { draftMode } from 'next/headers' import { redirect } from 'next/navigation' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import configPromise from '@payload-config' import { CollectionSlug } from 'payload' @@ -16,7 +16,7 @@ export async function GET( } }, ): Promise { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const token = req.cookies.get(payloadToken)?.value const { searchParams } = new URL(req.url) const path = searchParams.get('path') diff --git a/templates/website/src/app/(frontend)/posts/[slug]/page.tsx b/templates/website/src/app/(frontend)/posts/[slug]/page.tsx index 6aac4b77c5..7c5aecfb51 100644 --- a/templates/website/src/app/(frontend)/posts/[slug]/page.tsx +++ b/templates/website/src/app/(frontend)/posts/[slug]/page.tsx @@ -3,7 +3,7 @@ import type { Metadata } from 'next' import { RelatedPosts } from '@/blocks/RelatedPosts/Component' import { PayloadRedirects } from '@/components/PayloadRedirects' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { draftMode } from 'next/headers' import React, { cache } from 'react' import RichText from '@/components/RichText' @@ -15,7 +15,7 @@ import { generateMeta } from '@/utilities/generateMeta' import PageClient from './page.client' export async function generateStaticParams() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'posts', draft: false, @@ -82,7 +82,7 @@ export async function generateMetadata({ params: paramsPromise }: Args): Promise const queryPostBySlug = cache(async ({ slug }: { slug: string }) => { const { isEnabled: draft } = await draftMode() - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const result = await payload.find({ collection: 'posts', diff --git a/templates/website/src/app/(frontend)/posts/page.tsx b/templates/website/src/app/(frontend)/posts/page.tsx index cba764fede..b4f81bb048 100644 --- a/templates/website/src/app/(frontend)/posts/page.tsx +++ b/templates/website/src/app/(frontend)/posts/page.tsx @@ -4,7 +4,7 @@ import { CollectionArchive } from '@/components/CollectionArchive' import { PageRange } from '@/components/PageRange' import { Pagination } from '@/components/Pagination' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import PageClient from './page.client' @@ -12,7 +12,7 @@ export const dynamic = 'force-static' export const revalidate = 600 export default async function Page() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'posts', diff --git a/templates/website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx b/templates/website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx index 4f4d1e8c09..2aed497569 100644 --- a/templates/website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx +++ b/templates/website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx @@ -4,7 +4,7 @@ import { CollectionArchive } from '@/components/CollectionArchive' import { PageRange } from '@/components/PageRange' import { Pagination } from '@/components/Pagination' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import PageClient from './page.client' import { notFound } from 'next/navigation' @@ -19,7 +19,7 @@ type Args = { export default async function Page({ params: paramsPromise }: Args) { const { pageNumber } = await paramsPromise - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const sanitizedPageNumber = Number(pageNumber) @@ -70,7 +70,7 @@ export async function generateMetadata({ params: paramsPromise }: Args): Promise } export async function generateStaticParams() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'posts', depth: 0, diff --git a/templates/website/src/app/(frontend)/search/page.tsx b/templates/website/src/app/(frontend)/search/page.tsx index aac8fe9e79..841cc7e20d 100644 --- a/templates/website/src/app/(frontend)/search/page.tsx +++ b/templates/website/src/app/(frontend)/search/page.tsx @@ -2,7 +2,7 @@ import type { Metadata } from 'next/types' import { CollectionArchive } from '@/components/CollectionArchive' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import { Post } from '@/payload-types' import { Search } from '@/search/Component' @@ -15,7 +15,7 @@ type Args = { } export default async function Page({ searchParams: searchParamsPromise }: Args) { const { q: query } = await searchParamsPromise - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'search', diff --git a/templates/website/src/blocks/ArchiveBlock/Component.tsx b/templates/website/src/blocks/ArchiveBlock/Component.tsx index fdfbd1b3e3..1d509d5f2e 100644 --- a/templates/website/src/blocks/ArchiveBlock/Component.tsx +++ b/templates/website/src/blocks/ArchiveBlock/Component.tsx @@ -1,7 +1,7 @@ import type { Post, ArchiveBlock as ArchiveBlockProps } from '@/payload-types' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import RichText from '@/components/RichText' @@ -19,7 +19,7 @@ export const ArchiveBlock: React.FC< let posts: Post[] = [] if (populateBy === 'collection') { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const flattenedCategories = categories?.map((category) => { if (typeof category === 'object') return category.id diff --git a/templates/website/src/utilities/getDocument.ts b/templates/website/src/utilities/getDocument.ts index aa7b522313..0dcb5ed427 100644 --- a/templates/website/src/utilities/getDocument.ts +++ b/templates/website/src/utilities/getDocument.ts @@ -1,13 +1,13 @@ import type { Config } from 'src/payload-types' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { unstable_cache } from 'next/cache' type Collection = keyof Config['collections'] async function getDocument(collection: Collection, slug: string, depth = 0) { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const page = await payload.find({ collection, diff --git a/templates/website/src/utilities/getGlobals.ts b/templates/website/src/utilities/getGlobals.ts index 873c152615..d37a2aa03c 100644 --- a/templates/website/src/utilities/getGlobals.ts +++ b/templates/website/src/utilities/getGlobals.ts @@ -1,13 +1,13 @@ import type { Config } from 'src/payload-types' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { unstable_cache } from 'next/cache' type Global = keyof Config['globals'] async function getGlobal(slug: Global, depth = 0) { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const global = await payload.findGlobal({ slug, diff --git a/templates/website/src/utilities/getRedirects.ts b/templates/website/src/utilities/getRedirects.ts index 111f2fa066..8eac7f2cf5 100644 --- a/templates/website/src/utilities/getRedirects.ts +++ b/templates/website/src/utilities/getRedirects.ts @@ -1,9 +1,9 @@ import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { unstable_cache } from 'next/cache' export async function getRedirects(depth = 1) { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const { docs: redirects } = await payload.find({ collection: 'redirects', diff --git a/templates/with-vercel-website/src/app/(frontend)/[slug]/page.tsx b/templates/with-vercel-website/src/app/(frontend)/[slug]/page.tsx index 926f91ce8e..8cf49b88e3 100644 --- a/templates/with-vercel-website/src/app/(frontend)/[slug]/page.tsx +++ b/templates/with-vercel-website/src/app/(frontend)/[slug]/page.tsx @@ -2,7 +2,7 @@ import type { Metadata } from 'next' import { PayloadRedirects } from '@/components/PayloadRedirects' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { draftMode } from 'next/headers' import React, { cache } from 'react' import { homeStatic } from '@/endpoints/seed/home-static' @@ -15,7 +15,7 @@ import { generateMeta } from '@/utilities/generateMeta' import PageClient from './page.client' export async function generateStaticParams() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const pages = await payload.find({ collection: 'pages', draft: false, @@ -85,7 +85,7 @@ export async function generateMetadata({ params: paramsPromise }): Promise { const { isEnabled: draft } = await draftMode() - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const result = await payload.find({ collection: 'pages', diff --git a/templates/with-vercel-website/src/app/(frontend)/next/preview/route.ts b/templates/with-vercel-website/src/app/(frontend)/next/preview/route.ts index a68ef127ff..e6bcf65c2a 100644 --- a/templates/with-vercel-website/src/app/(frontend)/next/preview/route.ts +++ b/templates/with-vercel-website/src/app/(frontend)/next/preview/route.ts @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken' import { draftMode } from 'next/headers' import { redirect } from 'next/navigation' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import configPromise from '@payload-config' import { CollectionSlug } from 'payload' @@ -16,7 +16,7 @@ export async function GET( } }, ): Promise { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const token = req.cookies.get(payloadToken)?.value const { searchParams } = new URL(req.url) const path = searchParams.get('path') diff --git a/templates/with-vercel-website/src/app/(frontend)/posts/[slug]/page.tsx b/templates/with-vercel-website/src/app/(frontend)/posts/[slug]/page.tsx index 6aac4b77c5..7c5aecfb51 100644 --- a/templates/with-vercel-website/src/app/(frontend)/posts/[slug]/page.tsx +++ b/templates/with-vercel-website/src/app/(frontend)/posts/[slug]/page.tsx @@ -3,7 +3,7 @@ import type { Metadata } from 'next' import { RelatedPosts } from '@/blocks/RelatedPosts/Component' import { PayloadRedirects } from '@/components/PayloadRedirects' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { draftMode } from 'next/headers' import React, { cache } from 'react' import RichText from '@/components/RichText' @@ -15,7 +15,7 @@ import { generateMeta } from '@/utilities/generateMeta' import PageClient from './page.client' export async function generateStaticParams() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'posts', draft: false, @@ -82,7 +82,7 @@ export async function generateMetadata({ params: paramsPromise }: Args): Promise const queryPostBySlug = cache(async ({ slug }: { slug: string }) => { const { isEnabled: draft } = await draftMode() - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const result = await payload.find({ collection: 'posts', diff --git a/templates/with-vercel-website/src/app/(frontend)/posts/page.tsx b/templates/with-vercel-website/src/app/(frontend)/posts/page.tsx index cba764fede..b4f81bb048 100644 --- a/templates/with-vercel-website/src/app/(frontend)/posts/page.tsx +++ b/templates/with-vercel-website/src/app/(frontend)/posts/page.tsx @@ -4,7 +4,7 @@ import { CollectionArchive } from '@/components/CollectionArchive' import { PageRange } from '@/components/PageRange' import { Pagination } from '@/components/Pagination' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import PageClient from './page.client' @@ -12,7 +12,7 @@ export const dynamic = 'force-static' export const revalidate = 600 export default async function Page() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'posts', diff --git a/templates/with-vercel-website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx b/templates/with-vercel-website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx index 4f4d1e8c09..2aed497569 100644 --- a/templates/with-vercel-website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx +++ b/templates/with-vercel-website/src/app/(frontend)/posts/page/[pageNumber]/page.tsx @@ -4,7 +4,7 @@ import { CollectionArchive } from '@/components/CollectionArchive' import { PageRange } from '@/components/PageRange' import { Pagination } from '@/components/Pagination' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import PageClient from './page.client' import { notFound } from 'next/navigation' @@ -19,7 +19,7 @@ type Args = { export default async function Page({ params: paramsPromise }: Args) { const { pageNumber } = await paramsPromise - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const sanitizedPageNumber = Number(pageNumber) @@ -70,7 +70,7 @@ export async function generateMetadata({ params: paramsPromise }: Args): Promise } export async function generateStaticParams() { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'posts', depth: 0, diff --git a/templates/with-vercel-website/src/app/(frontend)/search/page.tsx b/templates/with-vercel-website/src/app/(frontend)/search/page.tsx index aac8fe9e79..841cc7e20d 100644 --- a/templates/with-vercel-website/src/app/(frontend)/search/page.tsx +++ b/templates/with-vercel-website/src/app/(frontend)/search/page.tsx @@ -2,7 +2,7 @@ import type { Metadata } from 'next/types' import { CollectionArchive } from '@/components/CollectionArchive' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import { Post } from '@/payload-types' import { Search } from '@/search/Component' @@ -15,7 +15,7 @@ type Args = { } export default async function Page({ searchParams: searchParamsPromise }: Args) { const { q: query } = await searchParamsPromise - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const posts = await payload.find({ collection: 'search', diff --git a/templates/with-vercel-website/src/blocks/ArchiveBlock/Component.tsx b/templates/with-vercel-website/src/blocks/ArchiveBlock/Component.tsx index fdfbd1b3e3..1d509d5f2e 100644 --- a/templates/with-vercel-website/src/blocks/ArchiveBlock/Component.tsx +++ b/templates/with-vercel-website/src/blocks/ArchiveBlock/Component.tsx @@ -1,7 +1,7 @@ import type { Post, ArchiveBlock as ArchiveBlockProps } from '@/payload-types' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import React from 'react' import RichText from '@/components/RichText' @@ -19,7 +19,7 @@ export const ArchiveBlock: React.FC< let posts: Post[] = [] if (populateBy === 'collection') { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const flattenedCategories = categories?.map((category) => { if (typeof category === 'object') return category.id diff --git a/templates/with-vercel-website/src/utilities/getDocument.ts b/templates/with-vercel-website/src/utilities/getDocument.ts index aa7b522313..0dcb5ed427 100644 --- a/templates/with-vercel-website/src/utilities/getDocument.ts +++ b/templates/with-vercel-website/src/utilities/getDocument.ts @@ -1,13 +1,13 @@ import type { Config } from 'src/payload-types' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { unstable_cache } from 'next/cache' type Collection = keyof Config['collections'] async function getDocument(collection: Collection, slug: string, depth = 0) { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const page = await payload.find({ collection, diff --git a/templates/with-vercel-website/src/utilities/getGlobals.ts b/templates/with-vercel-website/src/utilities/getGlobals.ts index 873c152615..d37a2aa03c 100644 --- a/templates/with-vercel-website/src/utilities/getGlobals.ts +++ b/templates/with-vercel-website/src/utilities/getGlobals.ts @@ -1,13 +1,13 @@ import type { Config } from 'src/payload-types' import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { unstable_cache } from 'next/cache' type Global = keyof Config['globals'] async function getGlobal(slug: Global, depth = 0) { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const global = await payload.findGlobal({ slug, diff --git a/templates/with-vercel-website/src/utilities/getRedirects.ts b/templates/with-vercel-website/src/utilities/getRedirects.ts index 111f2fa066..8eac7f2cf5 100644 --- a/templates/with-vercel-website/src/utilities/getRedirects.ts +++ b/templates/with-vercel-website/src/utilities/getRedirects.ts @@ -1,9 +1,9 @@ import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' import { unstable_cache } from 'next/cache' export async function getRedirects(depth = 1) { - const payload = await getPayloadHMR({ config: configPromise }) + const payload = await getPayload({ config: configPromise }) const { docs: redirects } = await payload.find({ collection: 'redirects', diff --git a/test/app/(app)/test/page.tsx b/test/app/(app)/test/page.tsx index 3ddab66cb5..b6921c27a5 100644 --- a/test/app/(app)/test/page.tsx +++ b/test/app/(app)/test/page.tsx @@ -1,8 +1,8 @@ import configPromise from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities' +import { getPayload } from 'payload' export const Page = async ({ params, searchParams }) => { - const payload = await getPayloadHMR({ + const payload = await getPayload({ config: configPromise, }) return
test ${payload?.config?.collections?.length}
diff --git a/test/fields/int.spec.ts b/test/fields/int.spec.ts index a4d9cadbdf..8b9afda3fc 100644 --- a/test/fields/int.spec.ts +++ b/test/fields/int.spec.ts @@ -1,9 +1,8 @@ import type { MongooseAdapter } from '@payloadcms/db-mongodb' import type { IndexDirection, IndexOptions } from 'mongoose' -import { reload } from '@payloadcms/next/utilities' import path from 'path' -import { type PaginatedDocs, type Payload, ValidationError } from 'payload' +import { type PaginatedDocs, type Payload, reload, ValidationError } from 'payload' import { fileURLToPath } from 'url' import type { NextRESTClient } from '../helpers/NextRESTClient.js' diff --git a/test/helpers/initPayloadInt.ts b/test/helpers/initPayloadInt.ts index 9514a4691f..87b8ca77ff 100644 --- a/test/helpers/initPayloadInt.ts +++ b/test/helpers/initPayloadInt.ts @@ -1,7 +1,7 @@ import type { Payload, SanitizedConfig } from 'payload' -import { getPayloadHMR } from '@payloadcms/next/utilities' import path from 'path' +import { getPayload } from 'payload' import { runInit } from '../runInit.js' import { NextRESTClient } from './NextRESTClient.js' @@ -19,9 +19,7 @@ export async function initPayloadInt( const { default: config } = await import(path.resolve(dirname, 'config.ts')) console.log('starting payload') - // need to use getPayloadHMR and not getPayload, as getPayloadHMR will be used in next handlers. If we use getPayload - // here, payload would be cached somewhere else - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) console.log('initializing rest client') const restClient = new NextRESTClient(payload.config) console.log('initPayloadInt done') diff --git a/test/live-preview/app/live-preview/_api/getDoc.ts b/test/live-preview/app/live-preview/_api/getDoc.ts index 2aee9a8c08..bc2a05441a 100644 --- a/test/live-preview/app/live-preview/_api/getDoc.ts +++ b/test/live-preview/app/live-preview/_api/getDoc.ts @@ -1,7 +1,7 @@ import type { CollectionSlug, Where } from 'payload' import config from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities/getPayloadHMR.js' +import { getPayload } from 'payload' export const getDoc = async (args: { collection: CollectionSlug @@ -9,7 +9,7 @@ export const getDoc = async (args: { draft?: boolean slug?: string }): Promise => { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) const { slug, collection, depth = 2, draft } = args || {} const where: Where = {} @@ -28,7 +28,9 @@ export const getDoc = async (args: { draft, }) - if (docs[0]) return docs[0] as T + if (docs[0]) { + return docs[0] as T + } } catch (err) { console.log('Error getting doc', err) } diff --git a/test/live-preview/app/live-preview/_api/getDocs.ts b/test/live-preview/app/live-preview/_api/getDocs.ts index d802e7202d..4d8fc2a442 100644 --- a/test/live-preview/app/live-preview/_api/getDocs.ts +++ b/test/live-preview/app/live-preview/_api/getDocs.ts @@ -1,8 +1,8 @@ import config from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities/getPayloadHMR.js' +import { getPayload } from 'payload' export const getDocs = async (collection: string): Promise => { - const payload = await getPayloadHMR({ config }) + const payload = await getPayload({ config }) try { const { docs } = await payload.find({ diff --git a/test/live-preview/app/live-preview/_api/getFooter.ts b/test/live-preview/app/live-preview/_api/getFooter.ts index 969ba180cf..9f4c98d61c 100644 --- a/test/live-preview/app/live-preview/_api/getFooter.ts +++ b/test/live-preview/app/live-preview/_api/getFooter.ts @@ -1,10 +1,10 @@ import config from '@payload-config' -import { getPayloadHMR } from '@payloadcms/next/utilities/getPayloadHMR.js' +import { getPayload } from 'payload' import type { Footer } from '../../../payload-types.js' export async function getFooter(): Promise