如何使用Nodejs开发交互式命令行应

#点击图片报名参加武汉、长沙源创会#

在过去五年中,Node.js使软件开发统一起来。您可以用Node.js做任何你能想到的事情,前端开发,服务器端脚本,跨平台桌面应用程序,跨平台移动应用程序,物联网等。编写命令行工具也比以往任何时候都更容易,因为Node.js——不仅是一个命令行工具,它还具有交互式,易用和开发耗时少等特点。

如果您是前端开发人员,那么您肯定听说过或者用过Gulp,AngularCLI,Cordova,Yeoman等。你有没有想过他们如何工作的?例如,就AngularCLI来说,通过运行诸如ngnewproject-name命令就能创建一个具有基本配置的Angular新项目。而Yeoman等工具也要求运行时输入最后帮助您自定义项目的配置。Yeoman中的一些生成器可帮助你将项目发布到生产环境中。这就是我们今天要学习的。

在SMASHINGMAG上的相关阅读:

ADetailedIntroductionToWebpack(详细介绍Webpack)

AnIntroductionToNode.jsAndMongoDB(介绍Node.js和MongoDB)

Server-SideRenderingWithReact,NodeAndExpress(使用React、Node和Express进行服务端渲染)

UsefulNode.jsTools,TutorialsAndResources(Node.js工具、教程及资源)

我们会在本教程中开发一个命令行程序,它会接收一个包含客户信息的CSV文件,然后使用SendGridAPI向这些客户发送电子邮件。下面是这篇教程的目录:

“Hello,World”

处理命令行参数

运行时用户输入

异步网络通信

美化CLI输出

使其成为shell命令

JavaScript之外

“Hello,World”

本教程假设你已经安装了Node.js。如果你还没有安装,请先安装。Node.js带有一个叫npm的包管理器。使用npm,你可以安装很多开源的包。在npm的官方网站可以看到这些包的完整列表。我们这个项目中会用到许多开源模块(稍后会用到更多)。现在先使用npm创建一个Node.js项目。

这里我创建了一个名为broadcast的目录,并在其中运行了npminit命令。然后提供了一些项目的基本信息,比如名称(name)、说明(description)、版本(version)和入口(entrypoint)。入口是指执行脚本时最开始执行的JavaScript文件。默认情况下,Node.js把index.js作为入口;不过在这个示例中,我们把入口改为broadcast.js了。运行npminit命令的时候,你会看到更多选项,比如Git库、许可证和作者。你可以输入某些值,也可以留空不填。

成功执行npminit之后你会发现当前目录下出现了一个package.json文件。这是我们的配置文件。现在,它保存着我们创建项目的时候输入的信息。如果你想更详细的了解package.json,可以看看npm的文档。

现在我们已经建立了项目,接下来开始写“HelloWorld”程序。先在项目中创建broadcast.js文件,它会是你的主文件。在文件中输入如下这段代码:

运行这段代码。

你可以看到控制台输出“helloworld”。你可以通过nodebroadcast.js来运行,也可以通过nodebroadcast来运行。Node.js能够识别这两种方式。

在package.json的文档中,提到了一个名为dependencies的选项。在这个选项中你可以申明想用于本项目的所有第三方模块以及它们的版本号。我曾提到我们会在开发这个工具的过程中使用很多第三方开源模块,因此,我们的package.json看起来是这样的:

我们会使用Async、Chalk、Commander、CSV、Inquirer.js和SendGrid,在教程进行的过程中,我们会逐步讲解这些模块的用法。

处理命令行参数

获取命令行参数并不困难,只需要使用process.argv就可以了。但解析这些参数的值和选项可是件累人的活。所以,与其重复发明轮子,不如直接用Commander模块。Commander是个开源的Node.js模块,用于帮助我们写可交互的命令行工具。它带来了很多用于解析命令行选项的特性,而且还支持git风格的子命令。我最喜欢的Commander特性是自动生成到屏幕的帮助信息。你不需要写多余的代码——只需要解析--help或-h选项就可以了。你在定义各种命令行选项的时候,它会自动生成--help帮助信息。让我们用一下看看:

这行命令会在你的Node.js项目中安装Commander模块。在npm命令中使用--save选项会自动将Commander包含在项目的依赖项(dependencies)中,上面曾提到它在package.json中定义。在我们这个示例中,所有依赖项都已经申明了,所以我们不需要运行这个命令。

可以看到,处理命令行参数很简单。我们已经完成了对--list选项的定义。现在只要是在--list选项之后的值都会保存在括号里申明的变量中——在本例中,叫list。你可以通过program命令来访问它,这个program是Commander的实例。目前这个程序只是通过--list来接收一个文件路径然后打印到控制台。

你一定也注意到了我们调用方法链中的一个方法,version。如果我们在运行命令的时候使用--version或-V作为参数,就会打印出作为参数转入到这个方法的值。

同样,如果运行命令的时候给出--help选项,它会打印出所有定义好的选项和子命令。本例中的输出是这样的:

现在我们已经可以从命令行参数中接收到文件路径,接下来开始使用CSV模块读取CSV文件。CSV模块提供处理CSV文件的全面解决方案。从创建CSV文件到进行解析,都可以用这个模块来实现。

因为我们打算使用SendGridAPI来发送电子邮件,所以用下面这个文档来作为CSV文件的示例。我们会使用CSV模块来读取数据,并显示出相应行中的姓名和电子邮件地址。

现在让我们来写一段程序,从CSV文件中读取数据并打印到控制台。

我们可以使用原生的文件系统(FileSystem)模块读取从命令行参数获取的文件。文件系统模块中预定义了事件,其中data事件会在读取到一块数据时触发。CSV模块提供的parse方法能将CSV文件拆分行,并多次触发data事件。每个data事件都会发送一个数组,包含每一列的数据。那么,在本例中会按下面的格式打印数据:

运行时用户输入

我们已经知道如何接收命令行参数并解析它们。但是如果想在运行时获取输入该怎么办呢?Inquirer.js模块能让我们接收不同类型的输入,包括纯文本、密码和可多选项的列表等。

在这个示例中,我们会在运行时接收用户输入的电子邮件地址和姓名。

首先,注意上例中我们创建了一个名为contactList的数组,我们用它保存来自CSV文件的数据。

Inquirer.js有一个叫做prompt的方法,它的参数是一组我们想在运行时提出的问题。在本例中就是我们想知道的发送者的姓名、电子邮件地址和电子邮件的主题。我们创建了一个叫questions的数组,用来保存这些问题。这个数组的元素是一个包含像类型(type)这类属性的对象,类型用于标识输入的是密码还是列表,或者其它。你可以在官方文档看到完整的类型列表。这里的name保存了用户输入所需要保存的信息的名称。prompt方法返回一个Promise对象,根据成功或者失败会调用不同的回调函数,当然这会在用户回答完所有问题之后进行。用户的回答通过then回调的参数answers来访问。执行上述代码会得到如下结果:

异步网络通信

现在我们可以从CSV文件读取收件人的数据,并从命令行输入获取发送者的资料,是时候发送电子邮件了。我们使用SendGridAPI来发送电子邮件。

为了使用SendGrid模块,我们需要取得APIkey。你可以在SendGrid的控制面板(需要创建一个账号)生成这个APIkey。生成之后,把它保存在环境变量SENDGRID_API_KEY中。在Node.js中可以使用process.env来访问环境变量。

在上面的,我们使用SendGridAPI和Async模块异步发送了一个电子邮件。Async模块是最强大的Node.js模块之一。异步回调常常导致回调地狱。如果存在非常多的异步调用,你最终会写出回调中使用回调的代码,无法停下来。对于JavaScript开发者来说,处理错误也变得极其复杂。Async模块帮助你解决回调地狱,它提供了大量诸如each、series、map这样的方法让事件变得简单。这些方法帮助我们写更容易维护的异步代码。

在这个示例中,异步使用SengGrid发送邮件优于同步发送。这样就可以根据反馈再发送后续请求。你可以使用Async模块中的each方法,就可以遍历contactList数组并调用__sendEmail方法。这个方法会接收收件人的详情,发送人详情,主题,以及一个异步回调函数。__sendEmail使用SengGridAPI发送电子邮件,你可以从SengGrid的官方文档深入了解SengGrid。邮件发送完成会立即触发异步回调,它会处理contactList数据中的下一个对象。

到此为止,我们就用Node.js创建了一个用CSV接收输入信息并发送电子邮件的命令行应用。

美化输出

我们的应用已经可以发送电子邮件了。现在再看看如何让输出更好看,比如那些错误或成功的消息。这里我们需要用到Chalk模块,这个模块用于命令行输出[译者注:原文是inputs,但从意思以下面的代码来看,这里作者应该是想说输出的内容,它首先是Chalk的输入,通过Chalk处理之后再输出到控制台]的样式。

在上面的代码中,我们在发送邮件的过程添加了回调函数,这个函数会在每次循环的异步调用成功或因为运行时错误中止时调用。如果循环未完成,我们会在控制台用红色字体打印它发送出的错误对象,否则,用绿色字体打印出成功的消息。

如果你阅读了Chalk的文档,你会发现它有很多选项用于给输出添加样式,包括一些控制台颜色(品红、黄色、蓝色等)、下划线或加粗文本。

使其成为shell命令

现在我们的工具已经完成了,接下来应该让它像普通的shell命令那样执行。首先,我们在broadcast.js的顶部添加一行申明,它会告诉shell如何执行脚本。

现在配置package.json使其可执行。

我们添加了一个叫bin的新属性,我们在这里提供了执行broadcast.js命令的名称。

最后一步是将这个脚本安装为全局脚本,之后就可以像普通的shell命令一样执行它了。

在执行这个命令前,请确保它们处于相同的项目目录下。安装完成后即可测试这个命令。

这个命令会打印出有效的选项,就像之前执行nodebroadcast--help的输出一样。现在发布这个工具的准备工作都已经完成了。

要记住一点:在开发过程中,如果你只是简单的执行broadcast命令的话,是看不到项目代码变动所带来的效果的。在运行broadcast的时候,你得意识到broadcast的路径并不在你所在的项目目录中。如果你希望它在的话,可以在项目目录中运行npmlink,它会自动在可执行命令和项目目录间创建一个符号连接,之后,你在项目目录中所做的变动都会在broadcast命令中体现出来。

JavaScript之外

实现这类CLI工具所涉及的知识远远超出单纯的JavaScript项目。比如,如果你有软件开发和IT方面的经验的话,开发过程中可能涉及到Bash工具。从编写脚本到使用cron任务来进行备份都可以使用Bash脚本来自动化。实际上,在Docker、Chef和Puppet成为标配之前,Bash简直就是救世主。不过,Bash脚本经常出问题,它们真的不适合出现在开发流程中。所以通常我们用Python、Java或者JavaScript等语言时,Bash很少成为开发的核心,因为在Bash中甚至写个简单的条件语句都需要查阅无数的文档并进行调试。

总结

无论怎么说,使用JavaScript可让整个过程变得更加简单和高效。所有的工具自动成为跨平台工具。如果要运行本机shell命令,如git,mongodb或heroku,可以使用Node.js中的ChildProcess模块轻松实现。这使您能够使用简单的JavaScript编写软件工具。

希望本教程对您有帮助。如果您有任何问题,请在下方评论或

我。

推荐阅读

进行数据挖掘的8个最佳开源工具

工具推荐

玩出个性和品牌,6款优质国产开源电商系统

用于仪表盘项目的7个优秀JavaScript库

java基础思维导图,让java不再难懂

适用于开发者的最佳Chrome扩展工具

实用贴

点击“阅读原文”







































北京怎么治疗白癜风
北京哪个白癜风好



转载请注明:http://www.nylrzx365.com/csgj/7948.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了