如何将我的脚本加载到node.js REPL中?

188

我有一个脚本foo.js,里面包含一些函数想要在REPL中使用。

有没有一种方法可以让Node执行我的脚本,然后跳入REPL并具有所有已声明的全局变量,就像我可以使用python -i foo.pyghci foo.hs一样?

12个回答

234

目前没有内置功能可以提供您描述的精确功能。不过,使用REPL中的.load命令是使用require的替代方法,用法如下:

.load foo.js

它按行加载文件,就像您在REPL中键入它一样。与require不同,它会将加载的命令弄脏REPL历史记录。但是,它具有可重复性的优点,因为它不像require一样被缓存。
哪种更适合您将取决于您的用例。

编辑:它的适用范围有限,因为它不适用于严格模式,但是三年后我学到了,如果你的脚本没有使用'use strict',你可以使用eval来加载你的脚本,而不会污染REPL历史记录:

var fs = require('fs');
eval(fs.readFileSync('foo.js').toString())

如果我想在异步回调中进入repl怎么办? - Chet
3
如果你的问题与现有的问题不匹配,你可以撰写一个新的StackOverflow问题。 :-) - vossad01
@Chet,你可以使用(async()=>{ more code })();加载另一个文件,并且它将共享相同的全局变量。 - nurettin
1
提示:如果你使用 macOS(或者其他类似的操作系统),可以在 REPL 中输入“.load ”(注意空格),然后从 Finder 中将文件拖放到终端中,以添加正确的路径到你的命令。如果你要处理的文件位于多个层级下,这会非常方便。 - jamesnotjim
我需要声明__dirname才能让它工作。此外,我将代码编写为一个 shell 脚本(为了可重用性)。否则,这是个很好的解决方案! - Dave F
@vossad01,然后看它被标记为重复项。 - James M. Lay

69

我总是使用这个命令

node -i -e "$(< yourScript.js)"

与Python中没有任何包时的功能完全相同。


2
有人知道如何在Windows命令提示符中使其工作吗?我已经在Bash中使其工作了,但在Windows中没有。 - Sharpiro
1
@Sharpiro:如果你安装了Git,那么你可以选择在Windows PC上安装一个迷你UNIX。我的意思是Git的正常Windows发行版。 - Juan Lanus
这个问题的烦人之处在于Node.js会打印出repl提示符然后再运行你的脚本,所以任何输出都会被卡在提示符后面。 https://dev59.com/IGoy5IYBdhLWcg3wnfci#45893494没有这个问题,但是为了实现这个解决方案,函数必须明确地分配给变量以结束进入repl命名空间,所以也不是很好。 - Radon Rosborough
1
这是问题的正确答案。非常有帮助。谢谢@George。 - Vinn

13

我制作了Vorpal.js,它通过将您的 node 应用程序转换为交互式命令行界面来解决这个问题。它支持 REPL 扩展,该扩展可以让您在运行应用程序的上下文中进入 REPL。

var vorpal = require('vorpal')();
var repl = require('vorpal-repl');

vorpal
  .delimiter('myapp>')
  .use(repl)
  .show()
  .parse(process.argv); 

然后您可以运行该应用程序,它将进入REPL。

$ node myapp.js repl
myapp> repl: 

12

另一种方法是将这些函数定义为全局函数。

global.helloWorld = function() { console.log("Hello World"); }

然后在REPL中预加载该文件:

node -r ./file.js

那么函数helloWorld可以直接在REPL中访问。


11
这是George的答案的bash函数版本:
noderepl() {
    FILE_CONTENTS="$(< $1 )"
    node -i -e "$FILE_CONTENTS"
}

如果您将此放入您的~/.bash_profile中,您可以像使用别名一样使用它,例如:
noderepl foo.js

2
我已经使用这个功能好几个月了,在切换到新的shell环境时,我丢失了一些设置,不得不重新追踪。所以既然我在这里,我想感谢你提供这个非常有用的函数。 - Xaekai

8
我创建了replpad,因为我厌倦了不断重新加载脚本。
只需通过以下方式安装它:npm install -g replpad 然后通过运行replpad来使用它。
如果您希望它监视当前目录和所有子目录中的所有文件,并在更改时将它们导入repl,请执行: replpad . 请查看网站上的视频以更好地了解其工作原理,并了解一些其他不错的功能,比如这些:
  • 通过每个核心函数添加的dox()函数,可以在repl中访问核心模块文档,例如fs.readdir.dox()
  • 通过每个通过npm安装的模块添加的dox()函数,在repl中访问用户模块readme,例如marked.dox()
  • 通过每个函数添加的src属性,访问函数的高亮源代码、函数定义位置(文件、行号)和函数注释或jsdocs(如果可能),例如express.logger.src
  • scriptie-talkie支持(请参见.talk命令)
  • 添加命令和键盘快捷方式
  • vim键绑定
  • 键映射支持
  • 通过匹配token插件实现括号匹配
  • 通过键盘快捷方式或.append命令将在repl中输入的代码附加回文件

参见:https://github.com/thlorenz/replpad


我不得不使用 CXX=clang++ npm install replpad 来解决错误 g++: error: unrecognized command line option '-stdlib=libc++' - ShadSterling
但是当我运行它时,它会失败并显示以下错误信息:```#

Fatal error in ../deps/v8/src/api.cc, line 1248

Check failed: !value_obj->IsJSReceiver() || value_obj->IsTemplateInfo().

Illegal instruction: 4```
- ShadSterling

7
为什么不将文件加载到交互式节点repl中?
node -h
-e, --eval script          evaluate script
-i, --interactive          always enter the REPL even if stdin

node -e 'var client = require("./build/main/index.js"); console.log("Use `client` in repl")' -i

然后您可以在package.json中添加脚本

"repl": "node -e 'var client = require(\"./build/main/index.js\"); console.log(\"Use `client` in repl\")' -i",

本文使用 node v8.1.2 进行测试。


2
为什么不直接使用 node -i -r "./build/main/index.js" 呢? - Bernardo Dal Corno

5

目前直接无法实现,但你可以在REPL中使用 mylib = require('./foo.js')。请记住,方法是导出的,而不是声明为全局变量。


1
我觉得这种方式比.load my_work.js更好,尽管需要一些额外的exports.working_var = ...声明,因为REPL在某些完全有效的javascript代码上会出现错误,例如多行注释(至少在我的readline配置中是如此)。 - chbrown

4
< p > < code > replpad 很棒,但是为了快速且方便地将一个文件加载到 node 中,导入它的变量并启动一个 repl ,你可以在你的 .js 文件的末尾添加以下代码。

if (require.main === module){
    (function() {
        var _context = require('repl').start({prompt: '$> '}).context;
        var scope = require('lexical-scope')(require('fs').readFileSync(__filename));
        for (var name in scope.locals[''] )
            _context[scope.locals[''][name]] = eval(scope.locals[''][name]);
        for (name in scope.globals.exported)
            _context[scope.globals.exported[name]] = eval(scope.globals.exported[name]);
    })();
}

如果您的文件名为src.js,运行node src.js将启动node,加载文件,启动REPL,并复制声明为var的所有对象以及任何导出的全局变量。

if (require.main === module)确保此代码不会在通过require语句包含src.js时执行。实际上,您可以在if语句内添加任何要在单独调试src.js时执行的代码。


3

这里还有一个建议:尝试使用以下代码:

#!/usr/bin/env node
'use strict';

const repl = require('repl');
const cli = repl.start({ replMode: repl.REPL_MODE_STRICT });
cli.context.foo = require('./foo'); // injects it into the repl

然后你只需要运行这个脚本,它将会把foo作为一个变量包含进来。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接