【Node.js】ES Moduleで__dirnameを使う方法

 

問題・背景|ReferenceError: __dirname is not defined in ES module scope

Node.jsで__dirnameを使用すると、現在のJavaScriptファイルが存在するフォルダーのパスを取得できる。

Node.jsを扱っている者なら、利用することが多い機能の1つだと思う。

 

がしかし、__dirnameはCommon JSでしかサポートされておらず、ES Moduleで利用しようとすると怒られてしまう。

ReferenceError: __dirname is not defined in ES module scope
This file is being treated as an ES module because it has a '.js' file extension and '/example/example/example/example/server/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.

約)__dirnameはES moduleスコープでは定義されていません。package.jsonで"type":"module"を指定していてかつ拡張子が.jsなので、このファイルはES moduleとして扱われます。CommonJSのScript(__dirnameのこと)を利用したい場合は、拡張子に.cjsを使用してください。

 

ちなみにこのエラーは次のコードを記述した際に発生した。

app.use(express.static(path.join(__dirname, '../client/build')));

 

この場合、素直に拡張子に.cjsを使用するなりpackage.jsonで"type":"commonjs"を記述するなりして、Common JSファイルとして取り扱えば済むのだが、どうしてもES Moduleを利用したいシーンもあるだろう。

解決策

結論として、この問題は{fileURLToPath}モジュールを利用することで解決できる。

まずは、Node.js側(index.jsファイル)にて、pathfileURLToPathをimportする。

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

 

次に、fileURLToPathを利用して、__dirnameの機能を疑似的に再現する。

const __filename = fileURLToPath(import.meta.url);

const __dirname = path.dirname(__filename);

 

これで、ES ModuleでもCommonJSの__dirname機能を再現できる。

 

How to fix "__dirname is not defined in ES module scope"