From d76116c2233feadd092ff75a1f39fafd7645829b Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 17:14:10 -0800 Subject: [PATCH 01/11] feat --- .../src/{withPayload.js => withPayload.ts} | 130 +++++++----------- packages/next/src/withPayload.utils.ts | 130 ++++++++++++++++++ packages/next/src/withPayloadLegacy.ts | 67 +++++++++ 3 files changed, 248 insertions(+), 79 deletions(-) rename packages/next/src/{withPayload.js => withPayload.ts} (73%) create mode 100644 packages/next/src/withPayload.utils.ts create mode 100644 packages/next/src/withPayloadLegacy.ts diff --git a/packages/next/src/withPayload.js b/packages/next/src/withPayload.ts similarity index 73% rename from packages/next/src/withPayload.js rename to packages/next/src/withPayload.ts index 60f02432e6f..1c5dff4b9e6 100644 --- a/packages/next/src/withPayload.js +++ b/packages/next/src/withPayload.ts @@ -1,11 +1,31 @@ +/* eslint-disable no-console */ +/* eslint-disable no-restricted-exports */ +import type { NextConfig } from 'next' + +import { + getNextjsVersion, + supportsTurbopackExternalizeTransitiveDependencies, +} from './withPayload.utils.js' +import { withPayloadLegacy } from './withPayloadLegacy.js' + +const poweredByHeader = { + key: 'X-Powered-By', + value: 'Next.js, Payload', +} + /** * @param {import('next').NextConfig} nextConfig * @param {Object} [options] - Optional configuration options * @param {boolean} [options.devBundleServerPackages] - Whether to bundle server packages in development mode. @default false - * - * @returns {import('next').NextConfig} * */ -export const withPayload = (nextConfig = {}, options = {}) => { +export const withPayload = ( + nextConfig: NextConfig = {}, + options: { devBundleServerPackages?: boolean } = {}, +): NextConfig => { + const nextjsVersion = getNextjsVersion() + + const supportsTurbopackBuild = supportsTurbopackExternalizeTransitiveDependencies(nextjsVersion) + const env = nextConfig.env || {} if (nextConfig.experimental?.staleTimes?.dynamic) { @@ -15,67 +35,9 @@ export const withPayload = (nextConfig = {}, options = {}) => { env.NEXT_PUBLIC_ENABLE_ROUTER_CACHE_REFRESH = 'true' } - if (process.env.PAYLOAD_PATCH_TURBOPACK_WARNINGS !== 'false') { - // TODO: This warning is thrown because we cannot externalize the entry-point package for client-s3, so we patch the warning to not show it. - // We can remove this once Next.js implements https://github.com/vercel/next.js/discussions/76991 - const turbopackWarningText = - 'Packages that should be external need to be installed in the project directory, so they can be resolved from the output files.\nTry to install it into the project directory by running' - - // TODO 4.0: Remove this once we drop support for Next.js 15.2.x - const turbopackConfigWarningText = "Unrecognized key(s) in object: 'turbopack'" - - const consoleWarn = console.warn - console.warn = (...args) => { - // Force to disable serverExternalPackages warnings: https://github.com/vercel/next.js/issues/68805 - if ( - (typeof args[1] === 'string' && args[1].includes(turbopackWarningText)) || - (typeof args[0] === 'string' && args[0].includes(turbopackWarningText)) - ) { - return - } - - // Add Payload-specific message after turbopack config warning in Next.js 15.2.x or lower. - // TODO 4.0: Remove this once we drop support for Next.js 15.2.x - const hasTurbopackConfigWarning = - (typeof args[1] === 'string' && args[1].includes(turbopackConfigWarningText)) || - (typeof args[0] === 'string' && args[0].includes(turbopackConfigWarningText)) - - if (hasTurbopackConfigWarning) { - consoleWarn(...args) - consoleWarn( - 'Payload: You can safely ignore the "Invalid next.config" warning above. This only occurs on Next.js 15.2.x or lower. We recommend upgrading to Next.js 15.4.7 to resolve this warning.', - ) - return - } - - consoleWarn(...args) - } - } - - const isBuild = process.env.NODE_ENV === 'production' - const isTurbopackNextjs15 = process.env.TURBOPACK === '1' - const isTurbopackNextjs16 = process.env.TURBOPACK === 'auto' - - if (isBuild && (isTurbopackNextjs15 || isTurbopackNextjs16)) { - throw new Error( - 'Payload does not support using Turbopack for production builds. If you are using Next.js 16, please use `next build --webpack` instead.', - ) - } - - const poweredByHeader = { - key: 'X-Powered-By', - value: 'Next.js, Payload', - } - - /** - * @type {import('next').NextConfig} - */ - const toReturn = { + const baseConfig: NextConfig = { ...nextConfig, env, - turbopack: { - ...(nextConfig.turbopack || {}), - }, outputFileTracingExcludes: { ...(nextConfig.outputFileTracingExcludes || {}), '**/*': [ @@ -88,6 +50,9 @@ export const withPayload = (nextConfig = {}, options = {}) => { ...(nextConfig.outputFileTracingIncludes || {}), '**/*': [...(nextConfig.outputFileTracingIncludes?.['**/*'] || []), '@libsql/client'], }, + turbopack: { + ...(nextConfig.turbopack || {}), + }, // We disable the poweredByHeader here because we add it manually in the headers function below ...(nextConfig.poweredByHeader !== false ? { poweredByHeader: false } : {}), headers: async () => { @@ -96,7 +61,6 @@ export const withPayload = (nextConfig = {}, options = {}) => { return [ ...(headersFromConfig || []), { - source: '/:path*', headers: [ { key: 'Accept-CH', @@ -112,20 +76,14 @@ export const withPayload = (nextConfig = {}, options = {}) => { }, ...(nextConfig.poweredByHeader !== false ? [poweredByHeader] : []), ], + source: '/:path*', }, ] }, serverExternalPackages: [ - // serverExternalPackages = webpack.externals, but with turbopack support and an additional check - // for whether the package is resolvable from the project root - ...(nextConfig.serverExternalPackages || []), - // Can be externalized, because we require users to install graphql themselves - we only rely on it as a peer dependency => resolvable from the project root. - // // WHY: without externalizing graphql, a graphql version error will be thrown // during runtime ("Ensure that there is only one instance of \"graphql\" in the node_modules\ndirectory.") 'graphql', - // External, because it installs import-in-the-middle and require-in-the-middle - both in the default serverExternalPackages list. - '@sentry/nextjs', ...(process.env.NODE_ENV === 'development' && options.devBundleServerPackages !== true ? /** * Unless explicitly disabled by the user, by passing `devBundleServerPackages: true` to withPayload, we @@ -208,6 +166,13 @@ export const withPayload = (nextConfig = {}, options = {}) => { 'libsql', 'require-in-the-middle', ], + plugins: [ + ...(incomingWebpackConfig?.plugins || []), + // Fix cloudflare:sockets error: https://github.com/vercel/next.js/discussions/50177 + new webpackOptions.webpack.IgnorePlugin({ + resourceRegExp: /^pg-native$|^cloudflare:sockets$/, + }), + ], resolve: { ...(incomingWebpackConfig?.resolve || {}), alias: { @@ -237,22 +202,29 @@ export const withPayload = (nextConfig = {}, options = {}) => { aws4: false, }, }, - plugins: [ - ...(incomingWebpackConfig?.plugins || []), - // Fix cloudflare:sockets error: https://github.com/vercel/next.js/discussions/50177 - new webpackOptions.webpack.IgnorePlugin({ - resourceRegExp: /^pg-native$|^cloudflare:sockets$/, - }), - ], } }, } if (nextConfig.basePath) { - toReturn.env.NEXT_BASE_PATH = nextConfig.basePath + baseConfig.env.NEXT_BASE_PATH = nextConfig.basePath } - return toReturn + if (!supportsTurbopackBuild) { + return withPayloadLegacy(nextConfig) + } else { + return { + ...baseConfig, + serverExternalPackages: [ + ...(baseConfig.serverExternalPackages || []), + 'drizzle-kit', + 'drizzle-kit/api', + 'sharp', + 'libsql', + 'require-in-the-middle', + ], + } + } } export default withPayload diff --git a/packages/next/src/withPayload.utils.ts b/packages/next/src/withPayload.utils.ts new file mode 100644 index 00000000000..167beb41a3f --- /dev/null +++ b/packages/next/src/withPayload.utils.ts @@ -0,0 +1,130 @@ +/** + * This was taken and modified from https://github.com/getsentry/sentry-javascript/blob/15256034ee8150a5b7dcb97d23eca1a5486f0cae/packages/nextjs/src/config/util.ts + * + * MIT License + * + * Copyright (c) 2012 Functional Software, Inc. dba Sentry + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import { readFileSync } from 'fs' + +function _parseInt(input: string | undefined): number { + return parseInt(input || '', 10) +} + +/** + * Represents Semantic Versioning object + */ +type SemVer = { + buildmetadata?: string + /** + * undefined if not a canary version + */ + canaryVersion?: number + major?: number + minor?: number + patch?: number + prerelease?: string +} + +// https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +const SEMVER_REGEXP = + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-z-][0-9a-z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-z-][0-9a-z-]*))*))?(?:\+([0-9a-z-]+(?:\.[0-9a-z-]+)*))?$/i + +/** + * Parses input into a SemVer interface + * @param input string representation of a semver version + */ +export function parseSemver(input: string): SemVer { + const match = input.match(SEMVER_REGEXP) || [] + const major = _parseInt(match[1]) + const minor = _parseInt(match[2]) + const patch = _parseInt(match[3]) + + const prerelease = match[4] + const canaryVersion = prerelease?.startsWith('canary.') + ? parseInt(prerelease.split('.')[1] || '0', 10) + : undefined + + return { + buildmetadata: match[5], + canaryVersion, + major: isNaN(major) ? undefined : major, + minor: isNaN(minor) ? undefined : minor, + patch: isNaN(patch) ? undefined : patch, + prerelease: match[4], + } +} + +/** + * Returns the version of Next.js installed in the project, or undefined if it cannot be determined. + */ +export function getNextjsVersion(): SemVer | undefined { + try { + const pkgUrl = import.meta.resolve('next/package.json') + const pkgJson = JSON.parse(readFileSync(new URL(pkgUrl), 'utf8')) + return parseSemver(pkgJson.version) + } catch { + return undefined + } +} + +/** + * Checks if the current Next.js version supports native debug ids for turbopack. + * This feature was first introduced in Next.js v15.6.0-canary.36 and marked stable in Next.js v16 + * + * @param version - version string to check. + * @returns true if Next.js version supports native debug ids for turbopack builds + */ +export function supportsTurbopackExternalizeTransitiveDependencies( + version: SemVer | undefined, +): boolean { + if (!version) { + return false + } + + const { canaryVersion, major, minor } = version + + if (major === undefined || minor === undefined) { + return false + } + + if (major > 16) { + return true + } + + if (major === 16) { + if (minor > 1) { + return true + } + if (minor === 1) { + if (canaryVersion !== undefined) { + // 16.1.0-canary.15+ + return canaryVersion >= 15 + } else { + // Assume that Next.js 16.1 inherits support for this feature from the canary release + return true + } + } + } + + return false +} diff --git a/packages/next/src/withPayloadLegacy.ts b/packages/next/src/withPayloadLegacy.ts new file mode 100644 index 00000000000..bf47d10ccae --- /dev/null +++ b/packages/next/src/withPayloadLegacy.ts @@ -0,0 +1,67 @@ +/* eslint-disable no-console */ +import type { NextConfig } from 'next' + +/** + * Applies config options required to support Next.js versions before 16.1.0 and 16.1.0-canary.15. + */ +export const withPayloadLegacy = (nextConfig: NextConfig = {}): NextConfig => { + if (process.env.PAYLOAD_PATCH_TURBOPACK_WARNINGS !== 'false') { + // TODO: This warning is thrown because we cannot externalize the entry-point package for client-s3, so we patch the warning to not show it. + // We can remove this once Next.js implements https://github.com/vercel/next.js/discussions/76991 + const turbopackWarningText = + 'Packages that should be external need to be installed in the project directory, so they can be resolved from the output files.\nTry to install it into the project directory by running' + + // TODO 4.0: Remove this once we drop support for Next.js 15.2.x + const turbopackConfigWarningText = "Unrecognized key(s) in object: 'turbopack'" + + const consoleWarn = console.warn + console.warn = (...args) => { + // Force to disable serverExternalPackages warnings: https://github.com/vercel/next.js/issues/68805 + if ( + (typeof args[1] === 'string' && args[1].includes(turbopackWarningText)) || + (typeof args[0] === 'string' && args[0].includes(turbopackWarningText)) + ) { + return + } + + // Add Payload-specific message after turbopack config warning in Next.js 15.2.x or lower. + // TODO 4.0: Remove this once we drop support for Next.js 15.2.x + const hasTurbopackConfigWarning = + (typeof args[1] === 'string' && args[1].includes(turbopackConfigWarningText)) || + (typeof args[0] === 'string' && args[0].includes(turbopackConfigWarningText)) + + if (hasTurbopackConfigWarning) { + consoleWarn(...args) + consoleWarn( + 'Payload: You can safely ignore the "Invalid next.config" warning above. This only occurs on Next.js 15.2.x or lower. We recommend upgrading to Next.js 15.4.7 to resolve this warning.', + ) + return + } + + consoleWarn(...args) + } + } + + const isBuild = process.env.NODE_ENV === 'production' + const isTurbopackNextjs15 = process.env.TURBOPACK === '1' + const isTurbopackNextjs16 = process.env.TURBOPACK === 'auto' + + if (isBuild && (isTurbopackNextjs15 || isTurbopackNextjs16)) { + throw new Error( + 'Payload does not support using Turbopack for production builds. If you are using Next.js 16, please use `next build --webpack` instead.', + ) + } + + const toReturn: NextConfig = { + ...nextConfig, + serverExternalPackages: [ + // serverExternalPackages = webpack.externals, but with turbopack support and an additional check + // for whether the package is resolvable from the project root + ...(nextConfig.serverExternalPackages || []), + // External, because it installs import-in-the-middle and require-in-the-middle - both in the default serverExternalPackages list. + '@sentry/nextjs', + ], + } + + return toReturn +} From ed704d00e45ddbfb5045e16e12ab6e346b7d823e Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 17:26:04 -0800 Subject: [PATCH 02/11] fixes --- packages/next/src/withPayload.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next/src/withPayload.ts b/packages/next/src/withPayload.ts index 1c5dff4b9e6..58230a6fb6c 100644 --- a/packages/next/src/withPayload.ts +++ b/packages/next/src/withPayload.ts @@ -211,7 +211,7 @@ export const withPayload = ( } if (!supportsTurbopackBuild) { - return withPayloadLegacy(nextConfig) + return withPayloadLegacy(baseConfig) } else { return { ...baseConfig, @@ -222,6 +222,8 @@ export const withPayload = ( 'sharp', 'libsql', 'require-in-the-middle', + // Prevents turbopack build errors by the thread-stream package which is installed by pino + 'pino', ], } } From e81dde66bb26d6493a15f0e215ce94712c1f4726 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 17:27:03 -0800 Subject: [PATCH 03/11] Update error message --- packages/next/src/withPayloadLegacy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/src/withPayloadLegacy.ts b/packages/next/src/withPayloadLegacy.ts index bf47d10ccae..48632634b8a 100644 --- a/packages/next/src/withPayloadLegacy.ts +++ b/packages/next/src/withPayloadLegacy.ts @@ -48,7 +48,7 @@ export const withPayloadLegacy = (nextConfig: NextConfig = {}): NextConfig => { if (isBuild && (isTurbopackNextjs15 || isTurbopackNextjs16)) { throw new Error( - 'Payload does not support using Turbopack for production builds. If you are using Next.js 16, please use `next build --webpack` instead.', + 'Your Next.js and Payload versions do not support using Turbopack for production builds. Please upgrade to Next.js 16.1.0-canary.15 or higher if you want to use Turbopack for builds.', ) } From 5ba5cbc98f77219082e42572b2a3c4f5dfc381f7 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 18:00:35 -0800 Subject: [PATCH 04/11] fix cjs --- packages/next/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/package.json b/packages/next/package.json index dd25e120066..f8678cf3651 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -85,7 +85,7 @@ "build": "pnpm build:reactcompiler", "build:babel": "rm -rf dist_optimized && babel dist --out-dir dist_optimized --source-maps --extensions .ts,.js,.tsx,.jsx,.cjs,.mjs && rm -rf dist && mv dist_optimized dist", "build:bundle-for-analysis": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && node ./bundle.js esbuild", - "build:cjs": "swc ./src/withPayload.js -o ./dist/cjs/withPayload.cjs --config-file .swcrc-cjs --strip-leading-paths", + "build:cjs": "swc ./src/withPayload.ts -o ./dist/cjs/withPayload.cjs --config-file .swcrc-cjs --strip-leading-paths", "build:debug": "pnpm build", "build:esbuild": "node bundleScss.js", "build:reactcompiler": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && pnpm build:types && pnpm build:esbuild && pnpm build:cjs", From 2bd330001138bb3c278a82d52a806a95fd87c712 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 18:18:07 -0800 Subject: [PATCH 05/11] fix cjs --- packages/next/package.json | 12 ++++++------ packages/next/src/index.js | 2 +- packages/next/src/{ => withPayload}/withPayload.ts | 0 .../next/src/{ => withPayload}/withPayload.utils.ts | 0 .../next/src/{ => withPayload}/withPayloadLegacy.ts | 0 5 files changed, 7 insertions(+), 7 deletions(-) rename packages/next/src/{ => withPayload}/withPayload.ts (100%) rename packages/next/src/{ => withPayload}/withPayload.utils.ts (100%) rename packages/next/src/{ => withPayload}/withPayloadLegacy.ts (100%) diff --git a/packages/next/package.json b/packages/next/package.json index f8678cf3651..954a397b40a 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -32,8 +32,8 @@ "default": "./src/index.js" }, "./withPayload": { - "import": "./src/withPayload.js", - "default": "./src/withPayload.js" + "import": "./src/withPayload/withPayload.ts", + "default": "./src/withPayload/withPayload.ts" }, "./layouts": { "import": "./src/exports/layouts.ts", @@ -85,7 +85,7 @@ "build": "pnpm build:reactcompiler", "build:babel": "rm -rf dist_optimized && babel dist --out-dir dist_optimized --source-maps --extensions .ts,.js,.tsx,.jsx,.cjs,.mjs && rm -rf dist && mv dist_optimized dist", "build:bundle-for-analysis": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && node ./bundle.js esbuild", - "build:cjs": "swc ./src/withPayload.ts -o ./dist/cjs/withPayload.cjs --config-file .swcrc-cjs --strip-leading-paths", + "build:cjs": "swc ./src/withPayload -d ./dist/cjs --config-file .swcrc-cjs --strip-leading-paths", "build:debug": "pnpm build", "build:esbuild": "node bundleScss.js", "build:reactcompiler": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && pnpm build:types && pnpm build:esbuild && pnpm build:cjs", @@ -155,9 +155,9 @@ "default": "./dist/prod/styles.css" }, "./withPayload": { - "import": "./dist/withPayload.js", - "require": "./dist/cjs/withPayload.cjs", - "default": "./dist/withPayload.js" + "import": "./dist/withPayload/withPayload.js", + "require": "./dist/cjs/withPayload/withPayload.cjs", + "default": "./dist/withPayload/withPayload.js" }, "./layouts": { "import": "./dist/exports/layouts.js", diff --git a/packages/next/src/index.js b/packages/next/src/index.js index 0b09f2dfde7..d9154a66aa9 100644 --- a/packages/next/src/index.js +++ b/packages/next/src/index.js @@ -1 +1 @@ -export { default as withPayload } from './withPayload.js' +export { default as withPayload } from './withPayload/withPayload.js' diff --git a/packages/next/src/withPayload.ts b/packages/next/src/withPayload/withPayload.ts similarity index 100% rename from packages/next/src/withPayload.ts rename to packages/next/src/withPayload/withPayload.ts diff --git a/packages/next/src/withPayload.utils.ts b/packages/next/src/withPayload/withPayload.utils.ts similarity index 100% rename from packages/next/src/withPayload.utils.ts rename to packages/next/src/withPayload/withPayload.utils.ts diff --git a/packages/next/src/withPayloadLegacy.ts b/packages/next/src/withPayload/withPayloadLegacy.ts similarity index 100% rename from packages/next/src/withPayloadLegacy.ts rename to packages/next/src/withPayload/withPayloadLegacy.ts From b3a3c1521cfabc5ef067b294f4599e99b71edbf3 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 19:12:15 -0800 Subject: [PATCH 06/11] use esbuild for creating cjs withPayload --- packages/next/bundleWithPayload.js | 20 ++++++++++++++++++++ packages/next/eslint.config.js | 7 ++++++- packages/next/package.json | 4 ++-- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 packages/next/bundleWithPayload.js diff --git a/packages/next/bundleWithPayload.js b/packages/next/bundleWithPayload.js new file mode 100644 index 00000000000..93701cb9df3 --- /dev/null +++ b/packages/next/bundleWithPayload.js @@ -0,0 +1,20 @@ +/** + * This file creates a cjs-compatible bundle of the withPayload function. + */ + +import * as esbuild from 'esbuild' +import path from 'path' + +await esbuild.build({ + entryPoints: ['dist/withPayload/withPayload.js'], + bundle: true, + platform: 'node', + format: 'cjs', + outfile: `dist/cjs/withPayload.cjs`, + splitting: false, + minify: true, + metafile: true, + tsconfig: path.resolve(import.meta.dirname, 'tsconfig.json'), + sourcemap: true, +}) +console.log('withPayload cjs bundle created successfully') diff --git a/packages/next/eslint.config.js b/packages/next/eslint.config.js index 2ff40e845c0..0936f8bd366 100644 --- a/packages/next/eslint.config.js +++ b/packages/next/eslint.config.js @@ -19,7 +19,12 @@ export const index = [ tsconfigRootDir: import.meta.dirname, projectService: { // See comment in packages/eslint-config/index.mjs - allowDefaultProject: ['bundleScss.js', 'bundle.js', 'babel.config.cjs'], + allowDefaultProject: [ + 'bundleScss.js', + 'bundle.js', + 'babel.config.cjs', + 'bundleWithPayload.js', + ], }, }, }, diff --git a/packages/next/package.json b/packages/next/package.json index 954a397b40a..177876fa11c 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -85,7 +85,7 @@ "build": "pnpm build:reactcompiler", "build:babel": "rm -rf dist_optimized && babel dist --out-dir dist_optimized --source-maps --extensions .ts,.js,.tsx,.jsx,.cjs,.mjs && rm -rf dist && mv dist_optimized dist", "build:bundle-for-analysis": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && node ./bundle.js esbuild", - "build:cjs": "swc ./src/withPayload -d ./dist/cjs --config-file .swcrc-cjs --strip-leading-paths", + "build:cjs": "node ./bundleWithPayload.js", "build:debug": "pnpm build", "build:esbuild": "node bundleScss.js", "build:reactcompiler": "rm -rf dist && rm -rf tsconfig.tsbuildinfo && pnpm build:swc && pnpm build:babel && pnpm copyfiles && pnpm build:types && pnpm build:esbuild && pnpm build:cjs", @@ -156,7 +156,7 @@ }, "./withPayload": { "import": "./dist/withPayload/withPayload.js", - "require": "./dist/cjs/withPayload/withPayload.cjs", + "require": "./dist/cjs/withPayload.cjs", "default": "./dist/withPayload/withPayload.js" }, "./layouts": { From 667846f8dcc2bb468e37fc2488d5336fab6acf27 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 19:25:45 -0800 Subject: [PATCH 07/11] target nodejs version --- packages/next/bundleWithPayload.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/next/bundleWithPayload.js b/packages/next/bundleWithPayload.js index 93701cb9df3..4c1e252dba1 100644 --- a/packages/next/bundleWithPayload.js +++ b/packages/next/bundleWithPayload.js @@ -16,5 +16,8 @@ await esbuild.build({ metafile: true, tsconfig: path.resolve(import.meta.dirname, 'tsconfig.json'), sourcemap: true, + minify: false, + // 18.20.2 is the lowest version of node supported by Payload + target: 'node18.20.2', }) console.log('withPayload cjs bundle created successfully') From 809649147fb4ea62ae0b80283f3fa410de586540 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 19:33:09 -0800 Subject: [PATCH 08/11] do not swallow error --- packages/next/src/withPayload/withPayload.utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next/src/withPayload/withPayload.utils.ts b/packages/next/src/withPayload/withPayload.utils.ts index 167beb41a3f..57b5cc6f20b 100644 --- a/packages/next/src/withPayload/withPayload.utils.ts +++ b/packages/next/src/withPayload/withPayload.utils.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ /** * This was taken and modified from https://github.com/getsentry/sentry-javascript/blob/15256034ee8150a5b7dcb97d23eca1a5486f0cae/packages/nextjs/src/config/util.ts * @@ -82,7 +83,8 @@ export function getNextjsVersion(): SemVer | undefined { const pkgUrl = import.meta.resolve('next/package.json') const pkgJson = JSON.parse(readFileSync(new URL(pkgUrl), 'utf8')) return parseSemver(pkgJson.version) - } catch { + } catch (e) { + console.error('Payload: Error getting Next.js version', e) return undefined } } From aba54fce71a44537a446c3bc011f80306816fa5c Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 20:32:36 -0800 Subject: [PATCH 09/11] fix cjs/esm support --- .../next/src/withPayload/withPayload.utils.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/next/src/withPayload/withPayload.utils.ts b/packages/next/src/withPayload/withPayload.utils.ts index 57b5cc6f20b..5ddb7dc776a 100644 --- a/packages/next/src/withPayload/withPayload.utils.ts +++ b/packages/next/src/withPayload/withPayload.utils.ts @@ -80,8 +80,19 @@ export function parseSemver(input: string): SemVer { */ export function getNextjsVersion(): SemVer | undefined { try { - const pkgUrl = import.meta.resolve('next/package.json') - const pkgJson = JSON.parse(readFileSync(new URL(pkgUrl), 'utf8')) + let pkgPath: string + + // Check if we're in ESM or CJS environment + if (typeof import.meta?.resolve === 'function') { + // ESM environment - use import.meta.resolve + const pkgUrl = import.meta.resolve('next/package.json') + pkgPath = new URL(pkgUrl).pathname + } else { + // CJS environment - use require.resolve + pkgPath = require.resolve('next/package.json') + } + + const pkgJson = JSON.parse(readFileSync(pkgPath, 'utf8')) return parseSemver(pkgJson.version) } catch (e) { console.error('Payload: Error getting Next.js version', e) From a7367c00844e2fe223e1d29b958fb750158d29f5 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 20:37:22 -0800 Subject: [PATCH 10/11] fix comments and console msgs --- packages/next/src/withPayload/withPayload.utils.ts | 11 ++++------- packages/next/src/withPayload/withPayloadLegacy.ts | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/next/src/withPayload/withPayload.utils.ts b/packages/next/src/withPayload/withPayload.utils.ts index 5ddb7dc776a..9b8fb1d9d94 100644 --- a/packages/next/src/withPayload/withPayload.utils.ts +++ b/packages/next/src/withPayload/withPayload.utils.ts @@ -101,11 +101,8 @@ export function getNextjsVersion(): SemVer | undefined { } /** - * Checks if the current Next.js version supports native debug ids for turbopack. - * This feature was first introduced in Next.js v15.6.0-canary.36 and marked stable in Next.js v16 - * - * @param version - version string to check. - * @returns true if Next.js version supports native debug ids for turbopack builds + * Checks if the current Next.js version supports Turbopack externalize transitive dependencies. + * This was introduced in Next.js v16.1.0-canary.3 */ export function supportsTurbopackExternalizeTransitiveDependencies( version: SemVer | undefined, @@ -130,8 +127,8 @@ export function supportsTurbopackExternalizeTransitiveDependencies( } if (minor === 1) { if (canaryVersion !== undefined) { - // 16.1.0-canary.15+ - return canaryVersion >= 15 + // 16.1.0-canary.3+ + return canaryVersion >= 3 } else { // Assume that Next.js 16.1 inherits support for this feature from the canary release return true diff --git a/packages/next/src/withPayload/withPayloadLegacy.ts b/packages/next/src/withPayload/withPayloadLegacy.ts index 48632634b8a..2c2f6f9bc15 100644 --- a/packages/next/src/withPayload/withPayloadLegacy.ts +++ b/packages/next/src/withPayload/withPayloadLegacy.ts @@ -33,7 +33,7 @@ export const withPayloadLegacy = (nextConfig: NextConfig = {}): NextConfig => { if (hasTurbopackConfigWarning) { consoleWarn(...args) consoleWarn( - 'Payload: You can safely ignore the "Invalid next.config" warning above. This only occurs on Next.js 15.2.x or lower. We recommend upgrading to Next.js 15.4.7 to resolve this warning.', + 'Payload: You can safely ignore the "Invalid next.config" warning above. This only occurs on Next.js 15.2.x or lower. We recommend upgrading to the latest supported Next.js version to resolve this warning.', ) return } @@ -48,7 +48,7 @@ export const withPayloadLegacy = (nextConfig: NextConfig = {}): NextConfig => { if (isBuild && (isTurbopackNextjs15 || isTurbopackNextjs16)) { throw new Error( - 'Your Next.js and Payload versions do not support using Turbopack for production builds. Please upgrade to Next.js 16.1.0-canary.15 or higher if you want to use Turbopack for builds.', + 'Your Next.js and Payload versions do not support using Turbopack for production builds. Please upgrade to Next.js 16.1.0-canary.3 or higher if you want to use Turbopack for builds.', ) } From 18d47215b37a6d00198d6f716676f9b6a49d9ee4 Mon Sep 17 00:00:00 2001 From: Alessio Gravili Date: Sun, 7 Dec 2025 21:02:28 -0800 Subject: [PATCH 11/11] fix withpayload imports --- next.config.mjs | 2 +- test/admin-root/next.config.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/next.config.mjs b/next.config.mjs index a7d7748fa54..59d971b1d34 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,6 @@ import bundleAnalyzer from '@next/bundle-analyzer' import { withSentryConfig } from '@sentry/nextjs' -import { withPayload } from './packages/next/src/withPayload.js' +import { withPayload } from './packages/next/src/withPayload/withPayload.js' import path from 'path' import { fileURLToPath } from 'url' diff --git a/test/admin-root/next.config.mjs b/test/admin-root/next.config.mjs index f78bcde47e8..d2bf5e15c2e 100644 --- a/test/admin-root/next.config.mjs +++ b/test/admin-root/next.config.mjs @@ -1,6 +1,6 @@ import bundleAnalyzer from '@next/bundle-analyzer' -import withPayload from '../../packages/next/src/withPayload.js' +import { withPayload } from '../../packages/next/src/withPayload/withPayload.js' import path from 'path' import { fileURLToPath } from 'url'