【问题标题】:how to write a Node.js file that can be called from command line as well as 'require()'d from other files?如何编写可以从命令行调用以及从其他文件中调用的 Node.js 文件?
【发布时间】:2018-08-06 15:35:51
【问题描述】:

我想编写一个 Node.js 源文件 (myCode.js),其中有一个函数,比如 foo(arg1, arg2,..),这样我就可以..

$ node ./myCode.js arg1 arg2

还有

// myOtherCode.js
var foo = require('./mycode')

有可能吗?目前我有一小堆这样的文件,它们的编码都像

return (
    function foo() {
        //...
    }
)()

我从节点命令行调用,例如

$ node ./myCode.js arg1 agr2

但现在我想将它们串在一个 javascript 中,该 javascript 将使用“node”或“npm script”从命令行调用(因此来自不同文件的所有功能都需要是“require()d”)。但如果需要,我也想保留单独运行它们的能力。

我知道当从 shell 提示符调用时,arg1、arg2 将变为 argv[2]、argv[3] 等等,当 'require()'d 时,它们将是函数参数。

这可能也意味着我需要将参数传递给'require()'?我怎样才能做到这一点?

[使用 Node.js 8.x [LTS] 版本,因此无法使用导出/导入语法]

【问题讨论】:

    标签: node.js command-line require


    【解决方案1】:

    对于命令行和程序包使用有不同的入口点是很常规的。在 Node.js 中解析 CLI 参数的常用方法是 process.argv.slice(2),因为 node 和脚本名称是前 2 个参数。

    对于包级可执行脚本,foo 函数从 index.js 入口点导出:

    module.exports = function foo(arg1, arg2) { /* ... */ };
    

    考虑到foo 需要字符串参数,bin/index.js CLI 可执行脚本可以简洁如下:

    require('..')(...process.argv.slice(2));
    

    两者都可以在 package.json 中指定:

    "main": "index.js",
    "bin": { "foo": "bin/index.js" }
    

    这可能也意味着我需要将参数传递给'require()'?我怎样才能做到这一点?

    无法将它们传递给require。如果脚本需要以编程方式接受参数,这意味着它应该用接受参数的工厂函数包装。

    快速而简单的解决方法是通过 process.argv 将参数传递给 CLI 可执行脚本。例如,一个允许使用动态参数调用可执行脚本的辅助函数:

    const decache = require('decache');
    
    function loadCliModule(name, ...args) {
        decache(name);
        const originalArgv = process.argv;
        process.argv = [...process.argv.slice(2), ...args];
        const binModule = require(name);
        process.argv = originalArgv;
        return binModule;
    }
    

    可以这样使用:

    const foo = invokeCliModule(require.resolve('./foo'), 'bar'); // foo expects process.argv[2]
    

    请注意,由于decache 的工作方式,它只解缓存已加载的模块。如果子模块使用process.argv,则应进行相应处理。

    这不应该在生产中完成,因为这种方法很老套,但它非常适合测试。

    一个自然的限制是从 CLI 传递的参数是字符串,因此函数应该包含样板代码以将它们转换为预期的数据类型(数字、布尔值等)。因此,最好将编程入口点和 CLI 入口点分开。

    如果有必要调用很多这样的脚本,这可能是实际问题,解决方案是创建单个 CLI 可执行脚本,该脚本使用 yargs 之类的库处理参数并调用其他文件中的函数那个。

    【讨论】:

    • 我正在尝试将一堆 shell 脚本转换为等效的。 Node.js 文件。这些脚本用于测试另一个软件,并通过控制/主脚本运行,但也可以单独运行。我的 Node.js 文件现在处于每个单独运行 (node <file> arg1 arg2) 的状态,但我希望将它们扩展为通过像 tape 这样的断言库运行,其中我需要 require() 它们。每个人都会returnOKNOTOK。所以同一个文件需要表现得像一个函数。
    • 这是问题中未涉及的重要细节。出于测试目的使用 hack 调用此类模块是完全可以接受的。我更新了答案。
    【解决方案2】:

    是的,这是可能的。您必须使用 process.argv 来检索传递的参数

    例如,如果我们需要控制台字符串“hello”,我们必须创建一个文件 包含此代码的“fileName.js”:

     let firstArgument = process.argv[_.indexOf(process.argv, '--firstArgument') + 1];
     console.log(firstArgument);
    

    然后在终端执行这个

     node ./fileName.js --firstArgument varValue
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多