As the source on Soen suggests several uses for working with the import.meta.url
Alternative for __dirname in Node when using the --experimental-modules flag, however what has not been said is that the purpose of the fileURLToPath
is in addition to "resolve" Urls with file://
, as the documentation itself demonstrates (url.fileURLToPath
):
fileURLToPath('file:///C:/path/'); // Saída: C:\path\ (Windows)
fileURLToPath('file://nas/foo.txt'); // Saída: \\nas\foo.txt (Windows)
fileURLToPath('file:///你好.txt'); // Saída: /你好.txt (POSIX)
fileURLToPath('file:///hello world'); // Saída: /hello world (POSIX)
That is, it adjusts to the operating system also, this is useful where it is really strict the need of the tabs for the specific operating system (Windows or POSIX) and to treat Urls that are encoded with "percentage".
If the need to get the path of the current script is not strict to the "folder separator" and the import.meta.url
does not carry the encoded URL, so you do not need the fileURLToPath
, we can simply work with the object URL
(see also https://developer.mozilla.org/en-US/docs/Web/API/URL), including the Node documentation itself suggests that:
Usually we need __dirname
to get another file on the same level as the script or module that is running, so just use this:
console.log(new URL('./foo.txt', import.meta.url));
Ready, the new URL
already treats the path, without needing to concatenate, without needing to do anything much more, of course this will return an object URL
, but the native functions are ready for this, for example if you want to read a file (I used the toString
just to see output, the ideal is to work with stream
)
Note that most (if not all) common methods to work with "stream" have the parameter that accepts <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> |
Examples:
import { readFileSync } from 'fs';
const output = readFileSync(new URL('./foo.txt', import.meta.url));
console.log(output.toString());
Whether to list the contents of a folder:
import { readdirSync } from 'fs';
readdirSync(new URL('./', import.meta.url)).forEach(function (dirContent) {
console.log(dirContent);
});
Now of course I agree that if the intention is to do a "log of its own" or things of the kind is even worth some things done "at hand" with creating your own __dirname
, but for the normal use of what Node.js already offers, within ESMODULES it is totally possible not to depend even on __filename
nor __dirname
, because the native resources with new URL
already solve.
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)
(only Node.js v12.2.0+) combined with import.meta.url
to load scripts at different levels of the current script level, as this already helps avoid the need for __dirname
, an example using the 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();
Content of foo-bar.js
:
module.exports = () => {
console.log('hello world!');
};
What would be similar to doing without "Ecmascript Modules":
const fooBar = require('./foo-bar');
@Luizfelipe the alternative is "you don’t need it", the idea is that if there is a path that works you don’t have to patch or do tricks to simulate __dirname and __filename, the new URL + import.meta.url already solve everything natively no strings needed ;)
– Guilherme Nascimento
@Luizfelipe what perfectly new URL + import.meta.url with native Apis resolve ;), as described in the answer.
– Guilherme Nascimento