andy pai's tils

How to Update __dirname in Node.js for ES Modules

Today I needed to update the __dirname variable in Node.js for ES modules. The sqlite-vss package I was using was throwing an error when I tried to import it into my project, so I needed to switch to using ES modules.

$ node
Welcome to Node.js v18.16.0.
Type ".help" for more information.
> const sqlite_vss = require('sqlite-vss')

Uncaught:
Error [ERR_REQUIRE_ESM]: require() of ES Module ./node_modules/sqlite-vss/src/index.js not supported. Instead change the require of index.js in null to a dynamic import() which is available in all CommonJS modules.

Step 1: Update package.json

The first step was to add {"type": "module"} in my package.json file.

Step 2: Use url to get back __dirname

To get __dirname back, I defined a constant that resolves to the inbuilt globals that were provided to CommonJS code using the url module and import.meta. The code below works since a new, standardized global called import.meta.url is provided by ESM.

import { fileURLToPath } from 'url'
const __dirname = fileURLToPath(new URL('.', import.meta.url))

From there, it's possible to use path.join() like you would normally

import { join } from 'path'
const filePath = join(__dirname, 'test.js')

Protip: Node.js 20.11 adds import.meta.dirname and import.meta.filename to ES Modules

When using Node.js >= 20.11, we no longer need to define __dirname. A dirname property is available on import.meta.

const __dirname = import.meta.dirname

For now, the import.meta is still not available in the Node.js REPL. The REPL will throw an error:

$ node
Welcome to Node.js v21.7.2.
Type ".help" for more information.

> import.meta.dirname
import.meta.dirname
       ^^^^

Uncaught SyntaxError:
Cannot use 'import.meta' outside a module