In most cases, using what is native to Node.js (with ES Modules), not external resources, the use of __filename
and __dirname
for most cases can be totally unnecessary. Most (if not all) of the native methods for reading (streaming) supports the new URL
+ import.meta.url
, exactly as the official documentation itself suggests:
As you can see in the description of the methods, the path
parameter shows the supported formats, and in them include the <URL>
, examples:
Method |
path param supports |
---|
fs.readFile(path[, options], callback) |
<string> , <Buffer> , <URL> , <integer> |
fs.readFileSync(path[, options]) |
<string> , <Buffer> , <URL> , <integer> |
fs.readdir(path[, options], callback) |
<string> , <Buffer> , <URL> |
fs.readdirSync(path[, options]) |
<string> , <Buffer> , <URL> , <integer> |
fsPromises.readdir(path[, options]) |
<string> , <Buffer> , <URL> |
fsPromises.readFile(path[, options]) |
<string> , <Buffer> , <URL> , <FileHandle> |
So with new URL('<path or file>', import.meta.url)
it solves and you don't need to be treating strings and creating variables to be concatenated later.
Examples:
See how it is possible to read a file at the same level as the script without needing __filename
or any workaround:
import { readFileSync } from 'fs';
const output = readFileSync(new URL('./foo.txt', import.meta.url));
console.log(output.toString());
List all files in the script directory:
import { readdirSync } from 'fs';
readdirSync(new URL('./', import.meta.url)).forEach((dirContent) => {
console.log(dirContent);
});
Note: In the examples I used the synchronous functions just to make it easier to copy and execute.
If the intention is to make a "own log" (or something similar) that will depend on third parties, it is worth some things done manually, but within the language and Node.js this is not necessary, with ESMODULES
it is totally possible not to depend on either __filename
and neither __dirname
, since native resources with new URL
with already solve it.
Note that if you are interested in using something like require
at strategic times and need the absolute path from the main script, you can use module.createRequire(filename)
(Node.js v12.2.0 + only) combined with import.meta.url
to load scripts at levels other than the current script level, as this already helps to avoid the need for __dirname
, an example using import.meta.url
with module.createRequire
:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
// foo-bar.js is a CommonJS module.
const fooBar = require('./foo-bar');
fooBar();
Source from foo-bar.js
:
module.exports = () => {
console.log('hello world!');
};
Which is similar to using without "ECMAScript modules":
const fooBar = require('./foo-bar');
__dirname
working in ES6, have a look – kgangadhar