ESMで__dirnameを使う - import.meta.urlの活用法

問題

package.json"type": "module"を設定するか.mjsファイルを使うと、__dirname__filenameが定義されません。ReferenceError: __dirname is not definedエラーが発生します。

解決方法

import { fileURLToPath } from 'url';
import path from 'path';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// 従来通り使用可能
const configPath = path.resolve(__dirname, '../config/settings.json');
const dataDir = path.join(__dirname, '../../data');

ポイント

  • import.meta.urlは現在のファイルのURLをfile:///Users/...形式で返します。fileURLToPathで通常のファイルパスに変換しないと、path.joinなどで使えません。
  • CommonJS(require)からESMへの移行時に最初にぶつかるのがこの問題です。ファイル上部にこの2行を追加するだけで、残りのコードはそのまま使えます。
  • Node.js 20.11以降ではimport.meta.dirnameimport.meta.filenameが内蔵されています。ただし、下位互換性のためには上記の方法が安全です。