解决 node-fetch ES 模块导入错误
问题描述
当在 Node.js 项目中尝试导入 node-fetch
时,开发者可能会遇到以下错误:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module
require() of ES modules is not supported.
这个错误表示你正在尝试使用 require()
语法来导入一个仅支持 ES 模块 (ESM) 的包。从 node-fetch
v3.0.0 开始,该包已转为纯 ESM 模块,不再支持 CommonJS 的 require()
导入方式。
解决方案
方案一:使用 Node.js 内置 fetch(推荐)
从 Node.js v18.0.0 开始,fetch API 已成为全局内置功能,无需额外安装:
// 直接使用全局 fetch
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
TIP
Node.js v18+ 内置的 fetch 处于实验阶段,但对于大多数用例已经足够稳定。
方案二:降级 node-fetch 版本
如果必须使用 node-fetch 且不想迁移到 ESM,可以降级到 v2 版本:
# 使用 npm
npm install node-fetch@2.6.6
# 使用 yarn
yarn add node-fetch@^2.6.6
降级后可以使用 CommonJS 语法:
const fetch = require('node-fetch');
方案三:迁移到 ES 模块
将你的项目转换为 ES 模块项目:
- 在
package.json
中添加:
{
"type": "module"
}
- 使用 ES 模块导入语法:
import fetch from 'node-fetch';
方案四:使用动态导入
对于 CommonJS 项目,可以使用动态导入:
// 方法一:简单封装
const fetch = (...args) =>
import('node-fetch').then(({ default: fetch }) => fetch(...args));
// 方法二:TypeScript 友好版本
import { RequestInfo, RequestInit, Response } from 'node-fetch';
const nodeFetch = async (url: RequestInfo, init?: RequestInit): Promise<Response> => {
const { default: fetch } = await import('node-fetch');
return fetch(url, init);
};
方案五:使用替代库
考虑使用其他兼容 CommonJS 的 HTTP 请求库:
# axios
npm install axios
# got
npm install got
# gaxios (Google的轻量级替代品)
npm install gaxios
使用示例(gaxios):
const { request } = require('gaxios');
const result = await request({
url: 'https://api.example.com/data',
responseType: 'json'
});
最佳实践建议
- 优先使用 Node.js 内置 fetch(如果使用 Node.js v18+)
- 新项目直接使用 ES 模块,在
package.json
中设置"type": "module"
- 现有 CommonJS 项目考虑使用动态导入或降级 node-fetch
- TypeScript 项目可以使用 tsx 工具无缝运行 TypeScript 和 ESM
# 使用 tsx 运行 TypeScript
npx tsx server.ts
总结
node-fetch
v3+ 仅支持 ES 模块是导致此错误的主要原因。根据你的项目需求和 Node.js 版本,可以选择使用内置 fetch、降级 node-fetch、迁移到 ESM 或使用动态导入等解决方案。对于新项目,建议直接使用 Node.js v18+ 的内置 fetch API,既无需额外依赖,又能获得最佳性能。
WARNING
无论选择哪种方案,都建议测试相关功能以确保兼容性和稳定性,特别是在生产环境中。