Skip to content

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がグローバルに組み込まれています:

javascript
// Node.js 18+ では追加パッケインストール不要
const response = await fetch('https://api.example.com/data');
const data = await response.json();

TIP

プロダクション環境でNode.js 18+を使用できる場合は、これが最も簡単でパフォーマンスの良い解決策です。

方法2: プロジェクトをESMに対応させる

package.jsontypeフィールドを追加:

json
{
  "type": "module"
}

その後、ESMのimport構文を使用:

javascript
import fetch from 'node-fetch';

方法3: 動的インポートを使用する

CommonJS環境でESMモジュールを使用する場合:

javascript
// CommonJS形式での動的インポート
const fetch = (...args) => 
  import('node-fetch').then(({ default: fetch }) => fetch(...args));

TypeScriptを使用する場合:

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形式が必要な場合:

bash
npm install node-fetch@2.6.6

または

bash
yarn add node-fetch@^2.6.6

WARNING

バージョン2系はメンテナンスモードであり、重要なバグ修正のみ提供されます。

方法5: 代替ライブラリの使用

他のHTTPクライアントライブラリを使用する選択肢もあります:

javascript
// axiosの使用例
const axios = require('axios');

const response = await axios.get('https://api.example.com/data');
javascript
// gotの使用例
const got = require('got');

const response = await got.get('https://api.example.com/data');

詳細なコード例

ESMプロジェクトの設定

json
// package.json
{
  "name": "my-project",
  "type": "module",
  "dependencies": {
    "node-fetch": "^3.0.0"
  }
}
javascript
// 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();

動的インポートの詳細実装

javascript
// 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)
};
javascript
// 使用例
const { getFetch } = require('./fetch-wrapper');

async function main() {
  const fetch = await getFetch();
  const response = await fetch('https://api.example.com/data');
  // ...
}

ベストプラクティス

  1. Node.jsのバージョン確認:18以上であれば組み込みfetchを優先
  2. プロジェクトのモジュールシステム統一:ESMかCommonJSのいずれかに合わせる
  3. 型安全性:TypeScriptを使用する場合は適切な型定義を導入
  4. エラーハンドリング:ネットワークリクエストには必ず例外処理を実装
javascript
// 適切なエラーハンドリングの例
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モジュールエラーは、以下のいずれかの方法で解決できます:

  1. Node.js 18+の組み込みfetchを使用
  2. プロジェクトをESMに移行
  3. 動的インポートを利用
  4. node-fetchをバージョン2系にダウングレード
  5. 代替ライブラリの採用

現在のプロジェクト環境と要件に応じて、最適な解決策を選択してください。新しいプロジェクトでは、Node.jsの組み込みfetchを使用することが最も推奨されるアプローチです。