'require'未在节点检查器的 repl 的控制台选项卡中定义



我尝试

require('fs').writeFileSync('o.json', JSON.stringify(anObject));

为了调试,我得到了RefrenceError: require is not defined.

这很奇怪。什么样的环境没有require

在Node.js中,require函数不是全局定义的。当您需要一个模块时,它的源代码由一个接受多个参数的函数包装,require就是其中之一:

(function (exports, require, module, __filename, __dirname) {/* your code */
});

当您查看任何源文件的内容时,都可以在Node Inspector中看到该包装器。

现在有两种不同的场景可以从Node Inspector的控制台评估代码:

  1. 已调试的进程正在运行。表达式是在全局上下文中计算的,即您只能访问全局定义的符号。CCD_ 5不在其中。

  2. 已调试进程在断点处暂停。表达式是在选择堆栈帧的上下文中计算的,并且可以访问当前范围中的所有变量(包括外部函数从闭包捕获的变量)。但是:大多数函数都不调用require,因此这个变量在任何闭包中都不会被捕获,您也无法访问它

我和一位Node核心开发人员就将require公开为全局符号进行了简短的交谈,因为这将简化从Node Inspector注入代码的过程,但我的论点还不够令人信服。

可以在节点检查器中使用require,方法是在"require"在范围内的地方点击断点(使用NodeJS v0.10.25测试,node-inspector@0.7.0-2):

一个示例(Node的超简单的2字节"REPL"):创建一个仅包含以下内容的文件(例如r.js):

0;

然后使用

$ node --debug-brk r.js

并以通常的方式启动节点检查器和浏览器,

-或-(使用来自NPM的节点调试模块)使用:

$ node-debug r.js

现在切换到浏览器中的节点检查器控制台,验证是否确实定义了require,然后对其执行一些操作,如:

> typeof require;
"function"
> fs = require('fs');
undefined
> fs.writeFileSync('bla.txt', 'blup');
undefined

并验证该文件是否已写入启动节点的目录中。

注意:节点检查器的浏览器部分可能会出现故障:当一个接一个地调试不同的脚本时,我通常需要刷新(导致调试器断开连接),然后重新启动node,直到脚本在浏览器中正确显示。

附言:这个方法与创建一个Perl"REPL"有着惊人的相似之处,它是以perl -de '0;'的形式运行的。。。巧合

FWIW,只需从node-debug _mocha开始,在断点处停止,并在右侧面板中选择调用堆栈上的最低帧,我就可以获得require()可用的上下文:require('fs')工作正常,但require('q')和其他安装的模块不工作,即使我指定了绝对路径。如果我找到解决方案,我会回来的。

require()在所有CommonJS环境中实现,包括Node.js,但不在浏览器控制台中实现,这正是node-inspector的基础(具体地说,是Blink Developer Tools):

> require
ReferenceError: require is not defined

我发现了一种非常简单的方法来实现这一点。

首先,node inspect进入目标进程($pid):

$node inspect -p $pid
connecting to 127.0.0.1:9229 ... ok

接下来,输入";调试REPL":

debug> repl
Press Ctrl+C to leave debug repl

接下来,通过process.mainModule:获取主模块的require功能的参考

> require = process.mainModule.require
[Function: function]

就是这样。如果我们想使用它,我们会像往常一样使用:

> dns = require('dns')
{ lookup: ,
  lookupService: ,
  Resolver: ,
  setDefaultResultOrder: ,
  setServers: ,
  ... }
> dns.lookup('google.com', function(){result = arguments})
{ callback: , family: 0, hostname: 'google.com', oncomplete:  }
> result
[ null,
  '142.251.16.139',
  4,
  callee: ,
  Symbol(Symbol.iterator):  ]

需要注意的几件事:

  • 这将污染目标进程的全局命名空间。在你的情况下,这可能是个问题,也可能不是
  • 这假设存在目标进程的主模块入口点
  • process.mainModulev14.0.0以来已弃用

最新更新