为啥 __dirname 没有在节点 REPL 中定义?
Posted
技术标签:
【中文标题】为啥 __dirname 没有在节点 REPL 中定义?【英文标题】:Why is __dirname not defined in node REPL?为什么 __dirname 没有在节点 REPL 中定义? 【发布时间】:2012-02-07 16:47:45 【问题描述】:从节点手册中我看到我可以使用__dirname
获取文件的目录,但是从 REPL 中这似乎是未定义的。这是我的误解还是错误在哪里?
$ node
> console.log(__dirname)
ReferenceError: __dirname is not defined
at repl:1:14
at REPLServer.eval (repl.js:80:21)
at Interface.<anonymous> (repl.js:182:12)
at Interface.emit (events.js:67:17)
at Interface._onLine (readline.js:162:10)
at Interface._line (readline.js:426:8)
at Interface._ttyWrite (readline.js:603:14)
at ReadStream.<anonymous> (readline.js:82:12)
at ReadStream.emit (events.js:88:20)
at ReadStream._emitKey (tty.js:320:10)
【问题讨论】:
__dirname
和 __filename
也是 not available when node
is called with the --experimental-modules
flag。
我在使用 eslint 时遇到了这个问题,我在 .eslintrc.json 文件中错误地设置了 "browser": true
而不是 "node": true
。
如果这里没有任何效果,那就是 hack ***.com/a/49879107/696535
【参考方案1】:
__dirname
仅在脚本中定义。它在 REPL 中不可用。
尝试编写脚本a.js
console.log(__dirname);
并运行它:
node a.js
你会看到__dirname
被打印出来。
添加背景说明:__dirname
表示“此脚本的目录”。在 REPL 中,您没有脚本。因此,__dirname
没有任何实际意义。
【讨论】:
另外你不能在 RequireJS 模块中使用一些全局变量。如果你在服务器端使用 RequireJS,请参阅***.com/questions/9027429/…。 是的,这真的应该添加到答案中,因为这就是我的目标。 不将其添加到 REPL 的加载脚本中是令人讨厌的。我想不出它不存在的任何原因...... 我在 REPL 中使用.load script.js
加载了一个脚本文件。太糟糕了 __dirname 在 script.js 中仍然不可用
点赞!当我想知道 wtf 正在发生时,为我节省了 15 分钟【参考方案2】:
在现有答案的基础上,您可以在 REPL 中定义它:
__dirname = path.resolve(path.dirname(''));
或者:
__dirname = path.resolve();
If no
path
segments are passed,path.resolve()
will return the absolute path of the current working directory.
或@Jthorpe 的替代方案:
__dirname = process.cwd();
__dirname = fs.realpathSync('.');
__dirname = process.env.PWD
【讨论】:
如果您使用nesh
,您可以将其定义为加载脚本的一部分;这很漂亮
或__dirname = process.cwd()
或__dirname=fs.realpathSync('.')
或__dirname = process.env.PWD
path.dirname
在最新的主要版本6.0.0
中似乎不再接受非字符串值,因此此答案中的第一个建议将不起作用。【参考方案3】:
如果您使用的是Node.js modules,则__dirname
和__filename
不存在。
来自Node.js documentation:
没有 require、exports、module.exports、__filename、__dirname
这些 CommonJS 变量在 ES 模块中不可用。
require
可以使用module.createRequire()
导入到 ES 模块中。
__filename
和__dirname
的等价物可以通过import.meta.url
在每个文件中创建:
import fileURLToPath from 'url';
import dirname from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
https://nodejs.org/docs/latest-v15.x/api/esm.html#esm_no_filename_or_dirname
【讨论】:
从技术上讲,这是这里唯一正确的答案。所有其他解决方案都使用当前工作目录。这与 __dirname 功能不同,后者实际上是保存当前正在运行的脚本的文件夹。 这是这个确切问题的完美答案。谢谢,对我帮助很大! @RaviLuthra 100% 正确。 同意这是这里唯一正确的答案“如果”问题与 ES6 模块类型的架构有关。导入语句需要引用最终传递给 __dirname 的路径,该路径实际上是保存当前正在运行的脚本的文件夹。 ——【参考方案4】:在 ES6 中使用:
import path from 'path';
const __dirname = path.resolve();
在使用--experimental-modules
调用节点时也可用
【讨论】:
REPL中不需要导入核心模块;它会为您即时加载它们。 这给出了当前工作目录,而不是当前.js
文件的目录。
@Dirbaio,当您在 REPL 中时,当前的 .js
文件会是什么?
@c24w 刚查了一下,好像给了CWD
这是错误的。 __dirname
是当前模块目录,但您的解决方案使其成为当前工作目录。这个废话是怎么得到这么多赞成的,我无法理解。【参考方案5】:
正如@qiao 所说,您不能在节点repl 中使用__dirname
。但是,如果您需要在控制台中使用此值,则可以使用path.resolve()
或path.dirname()
。虽然,path.dirname()
只会给你一个“。”所以,可能没有那么有帮助。请务必require('path')
。
【讨论】:
【参考方案6】:我也尝试使用 path.join(__dirname, 'access.log')
加入我的路径,但它抛出了同样的错误。
这是我修复它的方法:
我首先导入了path包并声明了一个名为__dirname
的变量,然后调用了resolve
path方法。
在 CommonJS 中
var path = require("path");
var __dirname = path.resolve();
在 ES6+ 中
import path from 'path';
const __dirname = path.resolve();
编码愉快.......
【讨论】:
我在节点 v15.3.0 上,不需要使用path.resolve()
。 __dirname
开箱即用。你的答案仍然与 ES6+ 相关吗?
@Zac __dirname 仅在使用 CommonJS 的 Node 14 或更高版本上可用。但是 ECMA 正在推动 ES 模块成为标准而不是 CommonJS。【参考方案7】:
-> 在 ES6 版本中使用:
import path from "path"
const __dirname = path.resolve();
-> 并像这样使用它,例如:
res.sendFile(path.join(__dirname ,'views','shop.html'))
【讨论】:
这不等同于__dirname
,而是process.cwd()
。例如,从不同目录运行脚本时会得到不同的结果。使用 ESM 时,更好的方法是使用 import.meta.url
。见nodejs.org/docs/latest-v14.x/api/esm.html#esm_import_meta 和***.com/questions/46745014/…【参考方案8】:
如果你有node __dirname not defined
和node --experimental-modules
,你可以这样做:
const __dirname = path.dirname(import.meta.url)
.replace(/^file:\/\/\//, '') // can be usefull
因为其他示例,只使用当前/pwd 目录而不是其他目录。
【讨论】:
【参考方案9】:看来你也可以这样做:
__dirname=fs.realpathSync('.');
当然,别忘了fs=require('fs')
(它在节点脚本中并不是真正的全局,它只是在模块级别定义)
【讨论】:
你不需要 REPL 中的核心模块;它会为您即时加载它们。【参考方案10】:我以 SYSTEM 用户身份从批处理文件运行脚本,所有变量(如 process.cwd()
、path.resolve()
和所有其他方法都会为我提供 C:\Windows\System32 文件夹的路径,而不是实际路径。在实验期间,我注意到当抛出错误时,堆栈包含节点文件的真实路径。
这是一种通过触发错误并从 e.stack 中提取路径来获取真实路径的非常老套的方法。不要使用。
// this should be the name of currently executed file
const currentFilename = 'index.js';
function veryHackyGetFolder()
try
throw new Error();
catch(e)
const fullMsg = e.stack.toString();
const beginning = fullMsg.indexOf('file:///') + 8;
const end = fullMsg.indexOf('\/' + currentFilename);
const dir = fullMsg.substr(beginning, end - beginning).replace(/\//g, '\\');
return dir;
用法
const dir = veryHackyGetFolder();
【讨论】:
如果你不是通过 REPL 运行它,你可以使用__dirname
和__filename
。
这是至少试图提供正确解决方案的唯一答案。
@c24w 我尝试了 __dirname、__filename 和其他所有内容。在我的情况下,没有标准解决方案有效。如果您对 github.com/DVLP/Unscheduler 感到无聊,这是我的项目,它从任务调度程序以 SYSTEM 身份运行进程。任何其他可行的标准解决方案显然都比我上面的 hack 更好:)【参考方案11】:
虽然它不是这个问题的解决方案,但我想添加它,因为它可以帮助其他人。
您应该在 dirname 之前有 两个下划线,不是一个下划线(__dirname
不是 _dirname
)。
NodeJS Docs
【讨论】:
__dirname(带两个下划线)在 REPL 中不起作用以上是关于为啥 __dirname 没有在节点 REPL 中定义?的主要内容,如果未能解决你的问题,请参考以下文章
__dirname 在带有 webpack 捆绑的节点 js 中不起作用
alert(__dirname) 在电子应用程序中没有产生任何输出