为了使用ES6模块,我在运行Node应用程序时使用了——experimental-modules标志。

然而,当我使用这个标志时,元变量__dirname不可用。是否有另一种方法来获得与此模式兼容的存储在__dirname中的相同字符串?


当前回答

另一个选择

import {createRequire} from 'module'; // need node v12.2.0

const require = createRequire(import.meta.url);
const __dirname = require.resolve.paths('.')[0];

其他回答

我使用这个选项,因为路径以file://开始,只需删除该部分。

const __filename = import.meta.url.slice(7);
const __dirname = import.meta.url.slice(7, import.meta.url.lastIndexOf("/"));

在你的项目根目录下创建一个名为root-dirname.js的文件:

import { dirname } from 'path'

const dn = dirname(new URL(import.meta.url).hostname)
const __dirname = process.platform === 'win32' ? dn.substr(1) : dn // remove the leading slash on Windows
export const rootDirname = __dirname

然后在需要项目根文件夹的路径时导入rootDirname。

除此之外,Rudolf Gröhling的答案也是正确的。

我还在NPM上发布了一个名为cross-dirname的包(从es-dirname派生而来)。该包使用Node.js (ESM和CJS), Deno和GJS进行测试。

例子:

import dirname from 'cross-dirname'

console.log(dirname())

因为其他答案虽然有用,但没有涵盖跨平台情况(Windows POSIX)和/或路径解析,而不是__dirname或__filename,在所有地方重复这种代码有点冗长:

import { dirname, join } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const somePath = join(__dirname, '../some-dir-or-some-file')

我刚刚发布了一个名为esm-path的NPM包来帮助完成这种循环任务,希望它也能对其他人有用。

它有文档记载,但在这里如何使用它:

import { getAbsolutePath } from 'esm-path'

const currentDirectoryPath = getAbsolutePath(import.meta.url)
console.log(currentDirectoryPath)

const parentDirectoryPath = getAbsolutePath(import.meta.url, '..')
console.log(parentDirectoryPath)

// Adapt the relative path to your case
const packageJsonFilePath = getAbsolutePath(import.meta.url, '../package.json')
console.log(packageJsonFilePath)

// Adapt the relative path to your case
const packageJsonFilePath = getAbsolutePath(import.meta.url, '..' , 'package.json')
console.log(packageJsonFilePath)

您可以使用来自新的Error()的堆栈。这个错误不需要被抛出,也不会停止程序的执行。堆栈的第一行始终是错误及其消息,第二行是调用错误的文件。

由于这是一个方法(可能在util.js文件中),getDirname()调用的实际位置实际上是错误堆栈的第三行。

export const getDirname = () => {
    // get the stack
    const { stack } = new Error();
    // get the third line (the original invoker)
    const invokeFileLine = stack.split(`\n`)[2];
    // match the file URL from file://(.+)/ and get the first capturing group
    //     the (.+) is a greedy quantifier and will make the RegExp expand to the largest match
    const __dirname = invokeFileLine.match(/file:\/\/(.+)\//)[1];
    return __dirname;
};