require('node-fetch')会出现ERR_REQUIRE_ESM错误。

80

我只是使用

const fetch = require('node-fetch')

我明白了

Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\Alex\Desktop\rollbot\node_modules\node-fetch\src\index.js from C:\Users\Alex\Desktop\rollbot\index.js not supported.
Instead change the require of C:\Users\Alex\Desktop\rollbot\node_modules\node-fetch\src\index.js in C:\Users\Alex\Desktop\rollbot\index.js to a 
dynamic import() which is available in all CommonJS modules.
{
  code: 'ERR_REQUIRE_ESM'
}

我的其他包都能工作,只有node-fetch出了问题。为了使用node-fetch,我该怎么办?

7个回答

89
我发现最新版的node-fetch已默认更改为ES模块。你可以采取以下步骤:
  1. 使用 npm uninstall node-fetch 卸载当前版本的node-fetch。
  2. 安装第二版:npm install node-fetch@2
这对我起作用了!

愿上帝保佑你,愿生你的母亲受到祝福。 - undefined

63

node-fetch 包的自述文件中:

node-fetch是一个仅支持ESM的模块 - 您无法使用require导入它。除非您自己使用ESM,否则建议您保持在构建了CommonJS的v2版本上。 我们将继续为其发布关键性bug修复。

如果您想使用require导入它,则降级到v2。

您的另一选择是使用异步的import('node-fetch').then(...)


7
最好使用Axios,因为ES、CommonJs和TypeScript配置的混淆导致了很多困惑。 - Ankit Kumar
5
安装第二个版本:npm install node-fetch@2 - snack overflow
使用yarn应该是yarn add node-fetch@2 - darth-coder

34

最新更新于2022年5月

您可能不再需要node-fetch

在最新版本的Node.js (18.0.0)中,默认启用了全局fetch(实验性功能)。

const res = await fetch('https://nodejs.org/api/documentation.json');
if (res.ok) {
  const data = await res.json();
  console.log(data);
}

通过这个添加,以下全局变量可用: fetch, FormData, Headers, Request, Response.

您可以使用命令行标志--no-experimental-fetch禁用此API。


26

在我的情况下,我个人发现使用 require('cross-fetch') 更容易。文档在这里:cross-fetch

它可以用于 CommonJS 和 ES6 模块。


2
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community
2
我曾经尝试使用 TypeScript 中的 node-fetch,但使用 cross-fetch 却没有遇到任何问题。 - Parik Tiwari
1
这就是答案。我浪费了太多时间尝试让 node-fetch 工作(v2 没有 TypeScript 类型,v3 只能在 ESM 中工作,而在 node.js 中 TS 对其支持不好,呃...)。而 cross-fetch 就是可以正常工作的。 - Mariusz Pawelski
1
阅读文档:Read the docscross-fetch是如何工作的? (...) 如果你在node环境下,它会提供给你node-fetch库。 它使用的是node-fetch v2,因此你应该降级node-fetch而不是添加另一个不必要的依赖层。 - Rafael Tavares
cross-fetch 只能在 httpS 上工作。 - M22

7

您可以使用动态导入的方式,在CommonJS中使用node-fetch@3。由于fetch已经是一个异步API,您可以定义一个包装器如下:

fetch.js

exports.fetch = async function (url, init) {
    const {default: fetch} = await import("node-fetch");
    return await fetch(url, init);
};

接下来,您可以像这样使用包装器:

const fetch = require("./fetch");

在TypeScript中,这个技巧不能直接使用,因为TypeScript会将动态导入转换为常规的 require。要解决这个问题,只需将普通的 fetch.js 添加到您的项目中,并添加类型声明:

fetch.d.ts

/**
 * @param { import("node-fetch").RequestInfo} url
 * @param {import("node-fetch").RequestInit} init
 * @returns {Promise<import("node-fetch").Response>}
 */
export function fetch(
    url: import("node-fetch").RequestInfo,
    init: import("node-fetch").RequestInit
): Promise<import("node-fetch").Response>;

cross-fetch是一个很好的替代方案,但它包装的是node-fetch的2.x版本,因此你将无法获得最新版本。


2

NodeJS支持两种不同的模块类型:

  • 最初的CommonJS模块,使用require()加载其他模块
  • 较新的ECMAScript模块(也称为ESM),使用import加载其他模块。

正如在node-fetch更改日志中提到的(2021年8月28日):

This module was converted to be a ESM only package in version 3.0.0-beta.10. node-fetch is an ESM-only module — you are not able to import it with require. We recommend you stay on v2 which is built with CommonJS unless you use ESM yourself. We will continue to publish critical bug fixes for it.

Alternatively, you can use the async import() function from CommonJS to load node-fetch asynchronously:

const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));

因此,您可以使用这个一行代码代替const fetch = require('node-fetch')

或者,您可以安装并加载模块node-fetch-commonjs,而不是尝试加载node-fetch。它是一个CommonJS包装器,围绕node-fetch提供兼容性:

const fetch = require('node-fetch-commonjs')

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接