payloadcms / next-payload

A utility to deploy Payload serverlessly within a Next.js app
308 stars 44 forks source link

getPayload is not a function / req.payload is a Promise? #103

Closed marpstar closed 5 months ago

marpstar commented 9 months ago

Until this weekend, I was somehow running next-payload, @payloadcms/bundler-webpack, and next@14.0.4-canary.18 and things were working just fine. Something changed and things started breaking again.

I'm fully aware that Next 14.x is problematic for just about everyone. The error I was receiving was getPayload is not a function. The error was originating within the withPayload handler. For some reason the line

const getPayload = require("@payloadcms/next-payload/getPayload")

Inside of next-app/node_modules/@payloadcms/next-payload/dist/middleware/withPayload.js is resolving to a Promise. So getPayload is a Promise, and it has no default property, so the call to getPayload() results in the error.

Local API works fine, it seems to only be the REST API (and therefore pretty much all of /admin).

I debugged into the method and tinkered with the code. If I correctly await that import, everything starts working fine.

Because req.payload is not being properly populated, the Payload context is unavailable to subsequent middleware.

I'm running all of the latest packages: next@14.0.4, next-payload@0.11.1, @payloadcms/webpack-bundler@1.0.5, @payloadcms/richtext-slate@1.3.1.

Can someone from the Payload team give an explanation why this might be the case?

Others on Discord are having the same problem: https://discord.com/channels/967097582721572934/1176610911860039680/1176610911860039680

Full withPayload update:

// const getPayload = require("@payloadcms/next-payload/getPayload").default;   // before -- compiled code wants .default
const getPayload = require("@payloadcms/next-payload/getPayload");  // note strip off `.default` here. 
const withPayload = (handler) => async (req, res) => {
    // Need to backfill req.originalUrl
    req.originalUrl = req.url;
    // Need to backfill req.get -
    // it's relied on within payload
    req.get = (headerName) => req.headers[headerName.toLowerCase()];
    console.log({getPayload})
    req.payload = await (await getPayload).default();     // after -- if we await getPayload, we can call `default()` and things move forward...
    return handler(req, res);
};
module.exports = withPayload;
//# sourceMappingURL=withPayload.js.map
marpstar commented 9 months ago

Related? https://github.com/vercel/next.js/discussions/37520

tiago-web commented 7 months ago

any fixes? I'm having the same issue

jacobsfletch commented 5 months ago

Hey there @marpstar and @tiago-web, this repo will soon be archived because it's been merged into the main Payload repo here: https://github.com/payloadcms/payload/tree/main/packages/next. Payload 3.0 ships with native support for Next.js and is currently out in beta here: https://github.com/payloadcms/payload-3.0-demo. I'm going to close this issue now but feel free to keep the conversation going either as a GitHub Discussion or on Discord. If think issue persists, feel free to open a new ticket on either the demo repo or the monorepo with the 3.x-beta label, and be sure to include a reproduction so we can fix it faster.