A Node.js Helper Function for Accessing the CommonJS Equivalent of __dirname in ES Modules.
tldr;
Put this in a helpers.js
or utils.js
file in your project and you’re good to go.
import { fileURLToPath } from 'url';
import { dirname } from 'path';
/**
* Given a file path, return the CJS equivalent of `__dirname`
* @param {String} importMetaUrl - Should be `import.meta.url`
* @returns {String}
*/
export function getDirname(importMetaUrl) {
return dirname(fileURLToPath(importMetaUrl));
}
Explaining the Code
If you’re switching to ES modules in Node.js you’re going to find a few global helpers are missing. One of the most common ones that I miss the most is the global __dirname
. You can’t just type that and get the current working directory of the file being executed.
No worries thought, the Node.js docs have you covered:
[some] CommonJS variables are not available in ES modules...
__dirname
can be created inside of each file viaimport.meta.url
.
And they give the following example in the docs:
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
Ok, that’s cool. But I don’t want to have to remember and type that every time I just want __dirname
in a file.
“So abstract it into a function in a helpers.js
file in your project, Jim!” That’s a good idea.
// /path/to/project/root/helpers.js
import { fileURLToPath } from 'url';
import { dirname } from 'path';
export function getDirname() {
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
return __dirname
}
Ah but that’s not going to work. Why? Because import.meta.url
is going to return a file:///
path to that specific helpers.js
file. So if you import getDirname
from a file deep in your project somewhere, it’s going to return the directory name of the helpers.js
file, not the directory of the file importing the function. Example:
// Let's say `helpers.js` lived here:
// /path/to/project/root/helpers.js
// And now you were gonna import `getDirname` from here:
// /path/to/project/root/components/layouts/MyThing.js
import { getDirname } from "../../helpers.js";
const __dirname = getDirname();
console.log(__dirname);
// -> /path/to/project/root
The problem is that import.meta.url
is specific to the file in which it is called.
Ok, we can get around that. Pass import.meta.url
as the first argument to getDirname
when invoking it. And modify the getDirname
function to take one parameter representing the file:///
path of the file invoking the function.
Here’s what your final code would look like:
// /path/to/project/root/helpers.js
import { fileURLToPath } from 'url';
import { dirname } from 'path';
export function getDirname(importMetaUrl) {
return fileURLToPath(dirname(importMetaUrl));
}
// /path/to/project/root/components/layouts/MyThing.js
import { getDirname } from "../../helpers.js";
const __dirname = getDirname(import.meta.url);
console.log(__dirname);
// -> /path/to/project/root/components/layouts
That’s it. A Node.js helper function for accessing the CommonJS equivalent of __dirname
in ES modules.