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.
このエラーは、node-fetchのバージョン3.0.0以降がESモジュール(ESM)のみのパッケージとなったために発生します。CommonJSのrequire()
構文では読み込めなくなりました。
主な原因
node-fetchバージョン3.0.0からの重要な変更点:
- ESM(ECMAScript Modules)のみのサポート
- CommonJSの
require()
でのインポートが非対応 - パッケージの
package.json
に"type": "module"
が指定されている
WARNING
Node.jsのネイティブESMサポートはバージョン12以降で利用可能ですが、適切な設定が必要です。
解決策
方法1: Node.jsの組み込みfetchを使用する(推奨)
Node.jsバージョン18以降では、fetch APIがグローバルに組み込まれています:
// Node.js 18+ では追加パッケインストール不要
const response = await fetch('https://api.example.com/data');
const data = await response.json();
TIP
プロダクション環境でNode.js 18+を使用できる場合は、これが最も簡単でパフォーマンスの良い解決策です。
方法2: プロジェクトをESMに対応させる
package.json
にtype
フィールドを追加:
{
"type": "module"
}
その後、ESMのimport構文を使用:
import fetch from 'node-fetch';
方法3: 動的インポートを使用する
CommonJS環境でESMモジュールを使用する場合:
// CommonJS形式での動的インポート
const fetch = (...args) =>
import('node-fetch').then(({ default: fetch }) => fetch(...args));
TypeScriptを使用する場合:
import { RequestInfo, RequestInit, Response } from 'node-fetch';
const fetch = async (url: RequestInfo, init?: RequestInit): Promise<Response> => {
const { default: fetch } = await import('node-fetch');
return fetch(url, init);
};
方法4: node-fetchのバージョンをダウングレード
どうしてもCommonJS形式が必要な場合:
npm install node-fetch@2.6.6
または
yarn add node-fetch@^2.6.6
WARNING
バージョン2系はメンテナンスモードであり、重要なバグ修正のみ提供されます。
方法5: 代替ライブラリの使用
他のHTTPクライアントライブラリを使用する選択肢もあります:
// axiosの使用例
const axios = require('axios');
const response = await axios.get('https://api.example.com/data');
// gotの使用例
const got = require('got');
const response = await got.get('https://api.example.com/data');
詳細なコード例
ESMプロジェクトの設定
// package.json
{
"name": "my-project",
"type": "module",
"dependencies": {
"node-fetch": "^3.0.0"
}
}
// server.js
import fetch from 'node-fetch';
async function getData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
}
getData();
動的インポートの詳細実装
// fetch-wrapper.js
let _fetch;
const initializeFetch = async () => {
if (!_fetch) {
const { default: fetch } = await import('node-fetch');
_fetch = fetch;
}
return _fetch;
};
module.exports = {
getFetch: () => initializeFetch().then(() => _fetch)
};
// 使用例
const { getFetch } = require('./fetch-wrapper');
async function main() {
const fetch = await getFetch();
const response = await fetch('https://api.example.com/data');
// ...
}
ベストプラクティス
- Node.jsのバージョン確認:18以上であれば組み込みfetchを優先
- プロジェクトのモジュールシステム統一:ESMかCommonJSのいずれかに合わせる
- 型安全性:TypeScriptを使用する場合は適切な型定義を導入
- エラーハンドリング:ネットワークリクエストには必ず例外処理を実装
// 適切なエラーハンドリングの例
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch failed:', error.message);
}
まとめ
node-fetchのESモジュールエラーは、以下のいずれかの方法で解決できます:
- Node.js 18+の組み込みfetchを使用
- プロジェクトをESMに移行
- 動的インポートを利用
- node-fetchをバージョン2系にダウングレード
- 代替ライブラリの採用
現在のプロジェクト環境と要件に応じて、最適な解決策を選択してください。新しいプロジェクトでは、Node.jsの組み込みfetchを使用することが最も推奨されるアプローチです。