使用--experimental-modules标志时,节点中__dirname的替代方法

时间:2017-10-14 13:17:55

标签: node.js ecmascript-6 es6-modules

我在运行节点应用程序时使用标志--experimental-modules以使用ES6模块。

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

12 个答案:

答案 0 :(得分:25)

在Node.js 10中,有一种不需要创建多个文件的替代方案:

import path from 'path';

const __dirname = path.dirname(new URL(import.meta.url).pathname);

答案 1 :(得分:19)

有关于通过import.meta公开这些变量的建议,但就目前而言,您需要一个我发现的here hacky解决方法:

// expose.js
module.exports = {__dirname};

// use.mjs
import expose from './expose.js';
const {__dirname} = expose;

答案 2 :(得分:9)

2021年最规范的方式

import { URL } from 'url'; // in Browser, the URL in native accessible on window

const __filename = new URL('', import.meta.url).pathname;
// Will contain trailing slash
const __dirname = new URL('.', import.meta.url).pathname;

忘记 join 从当前文件创建路径,只需使用 URL

const pathToAdjacentFooFile = new URL('./foo.txt', import.meta.url).pathname;
const pathToUpperBarFile = new URL('../bar.json', import.mera.url).pathname;

答案 3 :(得分:8)

在大多数情况下,使用 Node.js 原生的内容(带有 ES 模块),而不是外部资源,在大多数情况下使用 __filename__dirname 完全没有必要< /强>。大多数(如果不是全部)用于读取(流)的本机方法都支持 new URL + import.meta.url正如官方文档本身所建议的那样

正如您在方法说明中所见,path 参数显示了支持的格式,其中包括 <URL>,示例:

<头>
方法 路径参数支持
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>

因此,使用 new URL('<path or file>', import.meta.url) 可以解决问题,您无需处理字符串并创建稍后要连接的变量。

示例:

了解如何在不需要 __filename 或任何解决方法的情况下读取与脚本相同级别的文件:

import { readFileSync } from 'fs';

const output = readFileSync(new URL('./foo.txt', import.meta.url));

console.log(output.toString());

列出脚本目录下的所有文件:

import { readdirSync } from 'fs';

readdirSync(new URL('./', import.meta.url)).forEach((dirContent) => {
  console.log(dirContent);
});
<块引用>

注意:在示例中,我使用同步函数只是为了更容易复制和执行。

如果打算制作一个依赖第三方的“自己的日志”(或类似的东西),那么手动完成一些事情是值得的,但在语言和 Node.js 中这是没有必要的,用 {{ 1}} 完全有可能不依赖于 ESMODULES__filename,因为带有 __dirname 的原生资源已经解决了。


请注意,如果您有兴趣在战略时刻使用诸如 new URL 之类的东西并且需要来自主脚本的绝对路径,您可以结合使用 require(仅限 Node.js v12.2.0 +)使用 module.createRequire(filename) 在当前脚本级别以外的级别加载脚本,因为这已经有助于避免需要 import.meta.url,示例使用 __dirnameimport.meta.url

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(); 的来源:

foo-bar.js

这类似于使用没有“ECMAScript 模块”

module.exports = () => {
    console.log('hello world!');
};

答案 4 :(得分:3)

我用过:

import path from 'path';

const __dirname = path.resolve(path.dirname(decodeURI(new URL(import.meta.url).pathname)));

decodeURI很重要:测试系统路径中的已用空间和其他内容。

path.resolve()处理相对网址。

答案 5 :(得分:1)

import path from 'path';
const __dirname = path.join(path.dirname(decodeURI(new URL(import.meta.url).pathname)));

此代码也可在Windows上使用

答案 6 :(得分:0)

我也遇到了这个问题,我的解决方案:

<强> ./ SRC / app.mjs:

app.set('views', path.join(path.resolve('./src'), 'views'));

以下是有关我的文件夹组织的信息:

<强> ./ index.mjs

import server from './src/bin/www.mjs';
server.start();

<强> ./的package.json

"scripts": {
    "start": "node --experimental-modules ./index.mjs"
},

它在我的Windows PC上以__dirname返回正确的路径。

答案 7 :(得分:0)

我制作了此模块es-dirname,该模块将返回当前脚本的目录名。

import dirname from 'es-dirname'

console.log(dirname())

它在 Windows Linux 上的 CommonJs 脚本和 ES模块中均可工作。

如果由于我的项目中的脚本到目前为止一直在运行而发生错误,请在此处打开一个问题,但是在某些其他情况下可能会失败。因此,请勿在生产环境中使用它。这是一个临时解决方案,因为我确信Node.js团队将在不久的将来发布一种强大的方法来实现这一目标。

答案 8 :(得分:0)

对于节点10.12 + ...

假设您正在使用模块工作,则此解决方案应该可以工作,并且还为您提供__filename支持

import path from 'path';
import { fileURLToPath } from 'url';

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

令人高兴的是,距CommonJS模块的require()仅有两行代码。为此,您需要添加:

import { createRequireFromPath } from 'module';
const require = createRequireFromPath(__filename); 

答案 9 :(得分:0)

我使用此选项,因为路径以 Align( alignment: Alignment.bottomCenter, widthFactor: 1.0, heightFactor: 1.0, child: Container( width: 80, height: 80, decoration: BoxDecoration(color: Colors.deepPurpleAccent, shape: BoxShape.circle), child: IconButton(icon: Icon(Icons.search), onPressed: (){}), ), ) 开头,只需删除该部分即可。

file://

答案 10 :(得分:-1)

Geoff指出以下代码不是返回模块路径,而是返回工作目录。

import path from 'path';
const __dirname = path.resolve();

--experimental-modules

一起使用

答案 11 :(得分:-2)

process.cwd()

摘自文档:

process.cwd()方法返回当前的工作目录。 Node.js进程。