なぜ __dirname が消えたのか?最近 Node.js プロジェクトで require を import に切り替えた場合、壁に突き当たったかもしれません。現在のディレクトリにアクセスしようとすると、Node.js が ReferenceError をスローします。これは、ESモジュール(ESM)がデフォルトで __dirname や __filename などのグローバル変数を含んでいないためです。
CommonJS ではこれらの変数が自動的に提供されます。しかし、ESM はプラットフォームに依存しないように設計されています。ブラウザにはサーバーのような「ディレクトリ構造」が存在しないため、異なる環境間での ESM の一貫性を保つために、これらのグローバル変数は削除されました。Node.js 14 以降を使用している場合は、これらのパスを手動で再構築する必要があります。
解決策:import.meta.url を使用するパスを取得するには、import.meta.url を使用する必要があります。このプロパティは、file:///Users/dev/project/index.js のように、現在のモジュールの完全な URL を返します。その後、Node.js の組み込みユーティリティを使用して、この URL を標準のファイルパスに変換できます。
1. path モジュールと url モジュールをインポートするまず、ファイル URL とパス文字列を処理するために必要なツールを取り込みます。スクリプトの先頭に以下の行を追加してください。
import { fileURLToPath } from 'url';
import { dirname } from 'path';
2. 欠落しているグローバル変数を再現するわずか2行のコードで、__filename と __dirname を手動で定義できます。これにより、ESM コードでも従来と同じ感覚でパスを扱えるようになります。
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
3. すべてを組み合わせるスクリプトからの相対パスで config フォルダを指定する場合の、一般的なセットアップ例を以下に示します。
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// 例:設定ファイルのパスを結合する
const configPath = path.join(__dirname, 'config', 'settings.json');
console.log(`ターゲットパス: ${configPath}`);
修正のテストapp.mjs(または package.json で "type": "module" が設定されている場合は app.js)という名前のファイルを作成して、解決策を確認します。上記のロジックを貼り付けて実行してください。
node app.mjs
ターミナルにファイルとフォルダの絶対パスが表示されるはずです。これで ReferenceError は発生しません。
ESM ファイルパスに関するヒント### process.cwd() だけに頼らないショートカットとして process.cwd() を使いたくなるかもしれません。しかし、注意が必要です。process.cwd() はスクリプトが存在する場所ではなく、ターミナルコマンドを実行したディレクトリを返します。ルートフォルダから node ./src/app.js を実行した場合、process.cwd() と __dirname は異なる場所を指すことになります。
JSON ファイルを安全に読み込む多くの開発者は JSON ファイルを読み込むために __dirname を必要とします。最新の Node.js バージョン(v20.10+)では JSON の Import Attributes がサポートされていますが、古い LTS バージョンでは fs モジュールと __dirname の修正を組み合わせる方法が最も互換性の高い手法です。
import { readFileSync } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const rawData = readFileSync(path.join(__dirname, 'data.json'), 'utf8');
const data = JSON.parse(rawData);

