node-fetchでERR_REQUIRE_ESMエラーが発生する原因と解決方法
問題の概要
Node.jsプロジェクトでnode-fetch
を使用する際、以下のコードを実行するとエラーが発生します:
const fetch = require('node-fetch');
エラーメッセージ:
Error [ERR_REQUIRE_ESM]: require() of ES Module not supported.
Instead change the require to a dynamic import() which is available in all CommonJS modules.
このエラーは、node-fetchのバージョン3以降がES Modules (ESM) のみのパッケージとなったために発生します。
なぜこのエラーが発生するのか
Node.jsは2種類のモジュールシステムをサポートしています:
- CommonJS:
require()
とmodule.exports
を使用 - ES Modules (ESM):
import
とexport
を使用
node-fetchのバージョン3.0.0以降はESMのみで提供されるようになり、CommonJSのrequire()
では読み込めなくなったためこのエラーが発生します。
解決方法
方法1: node-fetchのバージョン2を継続使用
最も簡単な解決策は、CommonJS互換のバージョン2を使用することです:
npm uninstall node-fetch
npm install node-fetch@2
TIP
バージョン2も重要なバグ修正は継続して提供されるため、安定性を求める場合はこの方法がおすすめです。
方法2: 動的インポートを使用
CommonJS環境でESMモジュールを使用するには、動的インポートを活用します:
const fetch = (...args) =>
import('node-fetch').then(({ default: fetch }) => fetch(...args));
このワンライナーにより、非同期でnode-fetchを読み込むことができます。
方法3: ラッパーモジュールの作成
頻繁に使用する場合は、ラッパーファイルを作成する方法もあります:
fetch.js:
exports.fetch = async function (url, init) {
const { default: fetch } = await import("node-fetch");
return await fetch(url, init);
};
使用例:
const { fetch } = require("./fetch");
// 通常通り使用可能
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
方法4: 代替パッケージの使用
cross-fetch
CommonJSとESMの両方をサポートする互換パッケージ:
npm install cross-fetch
const fetch = require('cross-fetch');
WARNING
cross-fetchは現時点でnode-fetchのバージョン2をラップしているため、最新の機能は利用できません。
node-fetch-commonjs
CommonJS用に特別に設計されたバージョン:
npm install node-fetch-commonjs
const fetch = require('node-fetch-commonjs');
方法5: Node.js組み込みのfetch機能を使用
最新情報
Node.js 18.0.0以降では、実験的な機能としてグローバルなfetch APIが組み込まれています。
// Node.js 18+ では組み込みのfetchが使用可能
const res = await fetch('https://api.example.com/data');
if (res.ok) {
const data = await res.json();
console.log(data);
}
この機能はfetch
、FormData
、Headers
、Request
、Response
などのグローバルオブジェクトを提供します。
実験的機能について
組み込みfetchはまだ実験的な機能のため、本番環境で使用する場合は--no-experimental-fetch
フラグで無効化されていないか確認してください。
まとめ
解決方法 | 適用場景 | メリット | デメリット |
---|---|---|---|
バージョン2使用 | 安定性重視 | 簡単、互換性問題なし | 最新機能が使えない |
動的インポート | 最新版を使用したい | 最新機能が使える | 非同期処理が必要 |
代替パッケージ | 互換性重視 | 簡単に導入可能 | パフォーマンスや機能面での制限 |
Node.js組み込み機能 | Node.js 18+ユーザー | 追加パッケージ不要 | 実験的機能である |
プロジェクトの状況に応じて最適な解決方法を選択してください。特に、Node.js 18以降を使用している場合は、組み込みのfetch機能の利用を検討することをおすすめします。