できない.dev

Node.js の ESM で「__dirname is not defined」が解決できない

ES Modules では CommonJS の __dirname / __filename が定義されないためです。
import.meta.url から導出するか、Node 20.11 以降なら import.meta.dirname を使います。

#nodejs#esm#dirname#import-meta#modules

要約

ReferenceError: __dirname is not defined は、ファイルが ES Modules として実行され、CommonJS のグローバル __dirname / __filename が ESM には存在しないために起きます。import.meta.url から自前で算出するか、Node.js 20.11 以降なら import.meta.dirname を使えば解決します。

よくある原因

  1. ESM で実行されている: package.json"type": "module" がある、または拡張子が .mjs のため、CommonJS のグローバルが無い。
  2. __dirname は CJS 専用: __dirname / __filename / require は CommonJS ラッパーが注入する変数で、ESM スコープには注入されない。
  3. コピペ由来: CommonJS 前提のブログ記事のコードをそのまま ESM プロジェクトに持ち込んでいる。

解決策

1. import.meta.url から導出する(全バージョン対応)

import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
 
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

この手法は Node.js の公式 ESM ドキュメントで案内されている定番です。

2. import.meta.dirname を使う(Node 20.11+ / 21.2+)

新しめの Node ならワンライナーで済みます。

const dir = import.meta.dirname;   // __dirname 相当
const file = import.meta.filename; // __filename 相当

3. パス結合に使う

import { join } from "node:path";
const configPath = join(import.meta.dirname, "config.json");

import.meta.dirname は Node 20.11.0 / 21.2.0 で追加されたため、それ未満を含むサポート対象がある場合は解決策 1 を採用してください。

この記事は役立ちましたか?