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.0TIP
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"フィールドを参照することで、このエラーを効果的に回避できます。