payloadcms / payload

Payload is the open-source, fullstack Next.js framework, giving you instant backend superpowers. Get a full TypeScript backend and admin panel instantly. Use Payload as a headless CMS or for building powerful applications.
https://payloadcms.com
MIT License
24.59k stars 1.56k forks source link

node-fetch ESM compatibility issue in PayloadCMS Webpack bundle #8682

Open vrajpatelTH opened 1 week ago

vrajpatelTH commented 1 week ago

Link to reproduction

No response

Describe the Bug

I am encountering an issue with PayloadCMS where the node-fetch package causes an error in my application. The error message is:

require() of ES Module /node_modules/node-fetch/src/index.js from /node_modules/payload/dist/uploads/getExternalFile.js not supported. Instead change the require of index.js to a dynamic import() which is available in all CommonJS modules.

It seems that node-fetch, which is now ESM-only, is being bundled by Webpack in a way that uses require() rather than import(). This causes the error because require() is not supported for ESM modules.

Environment Details

To Reproduce

  1. Install the required packages, including payload (which automatically installs node-fetch).
  2. Create a media collection in PayloadCMS.
  3. Upload an image to the media collection.
  4. Attempt to crop the uploaded image and publish it.

When publishing, the following error appears:

   require() of ES Module /node_modules/node-fetch/src/index.js from /node_modules/payload/dist/uploads/getExternalFile.js not supported.

Code Snippet

Here’s the problematic part of the getExternalFile function found in the node_modules/payload/dist/uploads/getExternalFile.js package:

const getExternalFile = async ({ data, req, uploadConfig }) => {
    const { filename, url } = data;
    if (typeof url === 'string') {
        let fileURL = url;
        if (!url.startsWith('http')) {
            const baseUrl = req.get('origin') || `${req.protocol}://${req.get('host')}`;
            fileURL = `${baseUrl}${url}`;
        }
        const { default: fetch } = await Promise.resolve().then(() => /*#__PURE__*/ _interop_require_wildcard(require("node-fetch")));
        // Other logic...
    }
    throw new _errors.APIError('Invalid file url', 400);
};

Proposed Fix

Replacing the line:

const { default: fetch } = await Promise.resolve().then(() => /*#__PURE__*/ _interop_require_wildcard(require("node-fetch")));

with:

const { default: fetch } = await import('node-fetch');

should resolve the error, allowing the application to function as intended.

Attachments

A video demonstrating the issue and the error message is attached for further context.

https://github.com/user-attachments/assets/fc58c04c-2551-45fc-98cf-abfe94248b4a

Payload Version

2.30.0

Adapters and Plugins

No response

cbratschi commented 6 days ago

Duplicate of https://github.com/payloadcms/payload/issues/4421