ERR_PACKAGE_PATH_NOT_EXPORTEDエラーの解決法
問題の概要
Node.js環境でモジュールをインポートしようとした際に、次のようなエラーが発生することがあります:
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './cid' is not defined by "exports"
このエラーは、Node.jsパッケージが**ESモジュール(ESM)**として構成されている場合に、CommonJS方式(require())でサブパスのインポートを試みたときに発生します。
典型的なケースとして、orbit-db
と multiformats
パッケージを使用する以下のコード:
const OrbitDB = require('orbit-db');
を実行すると、次のエラーが報告されます:
Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: Package subpath './cid' is not defined by "exports" in .../package.json
エラーが発生する主な原因は、multiformats
パッケージが v1.0.0以降でESMモジュールに移行したため、CommonJSのrequire()
でのインポートがサポートされなくなった点にあります。
エラーメカニズムの本質
Node.jsのpackage.json
の "exports"
フィールドは、外部からアクセス可能なパスを制御します。モジュールがESM形式のみをエクスポートする場合、CommonJSのrequire()
でサブパスを読み込もうとするとこのエラーが発生します。
推奨解決策
方法1: orbit-dbのバージョンダウングレード(最速解決法)
最も簡単な解決方法は、orbit-dbのバージョンを0.26.0
にダウングレードし、CommonJS互換バージョンを使用することです:
package.json
を編集してorbit-db
のバージョンを固定:json"dependencies": { "orbit-db": "^0.26.0" }
依存関係を再インストール:
bashrm -rf node_modules package-lock.json npm install
このバージョンでは、multiformatsではなくcids
パッケージを使用しているため、ESM関連の問題が発生しません。
方法2: multiformatsの互換バージョンを明示的にインストール
orbit-dbの最新バージョンを維持する必要がある場合、以下のコマンドでmultiformatsを互換バージョンに固定します:
npm install multiformats@9.9.0
TIP
orbit-db@0.28.7
は multiformats@10.0.2
を使用しますが、multiformats@9.x
はESMモジュールではないため互換性があります。
方法3: ソースコードの修正(アプリケーション改修可能な場合)
モジュール側の修正が可能な場合、動的インポートを使用してESMモジュールを読み込むようにします:
修正前:
const { CID } = require('multiformats/cid')
修正後:
let CID;
import('multiformats/cid').then(module => {
CID = module.CID;
});
// 非同期処理が必要
ただし、この変更はアプリケーションのアーキテクチャが非同期処理に対応している必要があります。
// CommonJS方式のrequire
const { CID } = require('multiformats/cid');
// 非同期で動的インポート
const loadCID = async () => {
const { CID } = await import('multiformats/cid');
return CID;
};
その他のよくあるケースと解決法
IDEの自動インポートによる不正パス
開発ツールの自動インポート機能が間違ったパスを追加する場合があります:
// 誤った例: '/index', '/lib' が不要
import { useRef } from 'react/index';
import { getFirestore } from 'firebase-admin/lib/firestore';
// パッケージルートからのインポート
import { useRef } from 'react';
import { getFirestore } from 'firebase-admin/firestore';
重要
パッケージ提供の正規インポートパスは、package.json
の"exports"
フィールドで定義されています。/index
や/lib
のようなサブパスを独自に指定するのは避けましょう。
パッケージ固有のインポート方式変更
file-type
など特定のパッケージでは、ESM対応のために専用のローダーが必要な場合があります:
import { loadEsm } from 'load-esm';
const fileType = await loadEsm('file-type').then(module => module.fileType);
ESMとCJSの混在環境では動的インポートが有効ですが、アプリケーション全体の非同期処理設計が必要です。
予防策とベストプラクティス
依存関係のバージョン互換性確認:
bashnpm outdated npm ls [パッケージ名] # 依存ツリーのチェック
ESM移行時の段階的対応:
json{ "type": "module", // 全面移行時に設定 "imports": { ... } // カスタムインポート設定 }
公式ドキュメント参照:
環境変数での回避(一時的対策)
開発中のみの一時的回避策として--openssl-legacy-provider
を設定できますが、根本解決ではありません:
"scripts": {
"start": "set NODE_OPTIONS=--openssl-legacy-provider && node app.js"
}
まとめ
ERR_PACKAGE_PATH_NOT_EXPORTED
エラーは、主にESモジュール形式のパッケージをCommonJS方式で読み込もうとした場合に発生します。根本的な解決には以下が効果的です:
- 依存パッケージの互換バージョンを使用する(推奨)
- アプリケーションをESM仕様に移行する
- IDEの自動インポートを監視し、不正パスを修正する
Node.jsのモジュールシステムを理解し、package.json
の"exports"
フィールドを参照することで、このエラーを効果的に回避できます。