日常开发中,编写 Node.js 命令行工具来完成一些小任务是很常见的操作。其编写也不难,和日常编写 Node.js 代码并无二致。

package.json 中的 bin 字段

一个 npm 模块,如果在 package.json 中指定了 bin 字段,那说明该模块提供了可在命令行执行的命令,这些命令就是在 bin 字段中指定的。

package.json

{
"bin": {
"myapp": "./cli.js"
}
}

程序安装后会可在命令行执行 myapp 命令,实际执行的就是指定的这个 cli.js 文件。如果是全局安装,会将这个目标 js 文件映射到 prefix/bin 目录下,而如果是在项目中安装,则映射到 ./node_modules/.bin/ 目录下。

比如上面的示例,全局安装后会将 cli.js 映射到 /usr/local/bin/myapp 目录下。

# 查看项目中安装的所有可执行模块
$ ll node_modules/.bin
...
webpack -> ../webpack/bin/webpack.js
...

如果你的 npm 包只提供了一个可执行的命令,可直接将 bin 字段设置为目标文件,此时命令行中可执行的 CLI 命令名为 npm 包名(即 name 字段)。

{
"name": "my-program",
"version": "1.2.5",
"bin": "./path/to/program"
}

所以上面的配置和下面这个配置是等效的。

{
"name": "my-program",
"version": "1.2.5",
"bin": {
"my-program": "./path/to/program"
}
}

执行:

$ my-program 

CLI 命令的编写

为项目添加 README 文件是很常见的操作,每次都从零开始是没必要的。这时候就可以通过创建一个 README 模板,然后写一个 CLI 工具来生成到项目中。这样,将工具安装到全局或通过 npx 就可以方便地完成 README 文件的创建。

$ npx mkreadme
README.md created

初始化项目

$ npm init -y

修改 package.json 文件为如下内容:

{
"name": "mkreadme",
"bin": "./cli.js",
"version": "0.1.0",
"license": "MIT"
}

创建入口文件

$ touch cli.js

入口文件即 bin 字段所指向的文件,它可以是任何文件名,只需要在行首指定运行环境即可。Node.js 的 CLI 命令,期望的运行环境当然是 Node.js。

cli.js

 #!/usr/bin/env node
// 其他代码...

然后添加我们的功能代码,从远端获取一个 README 模板文件到本地。

cli.js

#!/usr/bin/env node

const fs = require("fs");

const https = require("https"); const TEMPLATE_FILE =

"https://raw.githubusercontent.com/wayou/readme-template/master/README.md"; const file = fs.createWriteStream("README.md");

https.get(TEMPLATE_FILE, resposne => {

resposne.pipe(file);

console.log("README.md created");

});

这里,我们将模板文件放远端的一个位置然后通过网络请求下载下来,而不是直接放到 npm 模块中。这样做的好处是后面可以随时更新我们的模板文件而无须重新发布这个 npm 模块。

调试

通过在当前开发目录进行 link 操作可进行本地调试。

$ npm link
link 操作的输出信息
npm WARN mkreadme@0.1.0 No description
npm WARN mkreadme@0.1.0 No repository field. up to date in 3.435s

found 0 vulnerabilities /Users/wayou/.nvm/versions/node/v11.14.0/bin/mkreadme -> /Users/wayou/.nvm/versions/node/v11.14.0/lib/node_modules/mkreadme/cli.js

/Users/wayou/.nvm/versions/node/v11.14.0/lib/node_modules/mkreadme -> /Users/wayou/Documents/dev/github/mkreadme

然后就可以在任何地方执行刚刚创建的 CLI 命令了。

$ mkreadme
README.md created

参数的获取

让命令支持参数可以实现更加灵活的功能。通过 process.argv 在代码中能够获取到来自命令行的输入。但需要注意它返回的参数列表中前两位是 Node.js 的路径和当前项目的路径,从第三个元素开始才是命令中用户输入的数据。

#!/usr/bin/env node

const fs = require("fs");

const https = require("https"); const TEMPLATE_FILE =

"https://raw.githubusercontent.com/wayou/readme-template/master/README.md"; + const [, , ...args] = process.argv; const file = fs.createWriteStream("README.md");

+ const url = args[0] || TEMPLATE_FILE;

+ https.get(url, resposne => {

resposne.pipe(file);

console.log("README.md created");

});

通过添加参数的支持,我们可以让使用者手动指定一个模板地址以下载对应的模板文件。

发布

最后一步就是发布出去,这样所有人就能安装使用了。

$ npm publish --access public

安装与使用

$ npm i -g mkreadme
$ mkreadme
README.md created

除了像上面将命令安装到全局使用外,个人更加推荐的方式是通过 npx。npx 会自动查找本机是否有安装相应模块,如果没有的话,自动去远端查找并执行。通过 npx 就不用安装到本地,每次运行都可以使用远端最新的版本。

$ npx mkreadme
README.md created

后续的优化

示例中只实现了基本的功能,作为一个功能健全的实用工具,可以做以下的优化:

  • 生成时做重名判断,如果已经存在 README 文件则提示是否覆盖。
  • 文件下载和创建过程中的异常处理及提示。
  • 提供并打印帮助信息,对使用者更加友好。
  • 对输出进行格式化,高亮输出相关信息,使信息更易读。

完整的示例

上面示例中的代码可在 mkreadme 这个仓库中找到。同时也发布到了 npm,可直接使用体验该工具。

三方工具

命令行工具能够打印帮助和使用信息是很重要的,如果自己输出的话,会面临格式化这些内容的麻烦。

如果提供的参数很多,解析处理用户输入的参数也是件很麻烦的事。

像参数校验,错误提示及帮助信息的输出,这些命令行工具基本的功能已经有三方库比较成熟地解决了,比如 commander.js。通过这个库可方便地编写更加复杂的命令行工具。

至于将输出信息进行高亮加彩色进行展示,也有相应三方库比如 chalk。

相关资源

Node.js 命令行工具的编写的更多相关文章

  1. 一个最简单 node.js 命令行工具

    一个最简单 node.js 命令行工具 node.js cli $ node cli.js xyz # OR $ node cli xyz 接受参数 process.argv js "use ...

  2. Node.js 命令行程序开发资料

    Node.js 命令行程序开发教程http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html用Node.js创建命令行工具ht ...

  3. Node.js 命令行程序开发教程

    nodejs开发命令行程序非常方便,具体操作方式查看下面几篇文章 http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html ...

  4. Node.js 命令行程序开发教程 ---------http://www.ruanyifeng.com/blog/2015/05/command-line-with-node.html

    五.yargs 模块 shelljs 只解决了如何调用 shell 命令,而 yargs 模块能够解决如何处理命令行参数.它也需要安装. $ npm install --save yargs yarg ...

  5. node命令行工具—cf-cli

    音乐分享: 钢心 - <龙王> 初喜<冠军>后喜<龙王> (PS:听一次钢心乐队的演出后采访才知道 “龙王”隐喻的是一起喝酒的老铁....) ——————————— ...

  6. 从零开始打造个人专属命令行工具集——yargs完全指南

    前言 使用命令行程序对程序员来说很常见,就算是前端工程师或者开发gui的,也需要使用命令行来编译程序或者打包程序 熟练使用命令行工具能极大的提高开发效率,linux自带的命令行工具都非常的有用,但是这 ...

  7. 如何用Node编写命令行工具

    0. 命令行工具 当全局安装模块之后,我们可以在控制台下执行指定的命令来运行操作,如果npm一样.我把这样的模块称之为命令行工具模块(如理解有偏颇,欢迎指正) 1.用Node编写命令行工具 在Node ...

  8. Node.js躬行记(3)——命令行工具

    一.自定义 创建一个空目录,然后通过npm init命令初始化package.json文件,并按提示输入相关信息或直接回车使用默认信息,生成的内容如下所示. { "name": & ...

  9. 微软开放技术发布针对 Mac 和 Linux 的更新版 Azure Node.JS SDK 和命令行工具

    发布于 2013-12-04 作者 Eduard Koller 这次为我们使用Linux 的朋友带来了更多关于部署云上虚拟机的消息.今天,微软开放技术有限公司 (MS Open Tech),想与大家分 ...

随机推荐

  1. django(权限、认证)系统—— Permissions和Group

    接着上面的3篇讨论文章,我们阐述了Django中如何使用Authentication系统进行,用户的创建,登陆,登出,完成了用户的认证.接下来,我们要看另外一个议题,那就是Authorization授 ...

  2. SQL Server 中如何做到连续时间段的拆分?

    今天在工作中遇到了一个很实际的问题,客户在OA接口的员工休假中间表中提供了连续时间段的休假记录,例如: 张三,2018-12-1 ~2018-12-31 ,病假,31天.这样带来的问题是,如果我需要统 ...

  3. 记一次springboot项目,maven引发的悲剧(Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletCont)

    maven下载大的项目的时候,jar包下载出错是常见的, 但是这种情况经常能看到,如java.lang.ClassNotFoundException这样的提示, 所以一直以来也觉得maven下载jar ...

  4. 死磕 java集合之ConcurrentLinkedQueue源码分析

    问题 (1)ConcurrentLinkedQueue是阻塞队列吗? (2)ConcurrentLinkedQueue如何保证并发安全? (3)ConcurrentLinkedQueue能用于线程池吗 ...

  5. 【Azkaban搭建】---Azkaban 3.25.0搭建细则 超实用

    一.前述 Azkaban是一个工作流调度工具,因为需要各个任务之间有依赖关系,传统的Crontab 任务已经不能满足. 所以需要建立一套工作流引擎.相比Ooize来说,Azkaban的优势是作为一个客 ...

  6. java游戏开发杂谈 - java编程怎么学

    java语言包含很多的知识点,我们并不需要把java语言的知识点都学全了,才开始编程.      你只需要了解: 1,java的数据类型和变量定义 2,类和对象的初步印象. 3,if-else, wh ...

  7. 很详细的Django入门详解

    Django 是用Python开发的一个免费开源的Web框架,可以用于快速搭建高性能,优雅的网站!采用了MVC的框架模式,即模型M,视图V和控制器C,也可以称为MVT模式,模型M,视图V,模板T.在学 ...

  8. 学习 JavaScript (六)核心概念:函数

    基本知识 函数对于我们来说,不算陌生的东西.中学就已经有了函数的概念,比如: y = f(x) 输入一个数 x,能够得到与之对应的一个数 y.也就是说,f(x) 的有一个返回值,这是函数在数学上的定义 ...

  9. NumPy 超详细教程(2):数据类型

    系列文章地址 NumPy 最详细教程(1):NumPy 数组 NumPy 超详细教程(2):数据类型 NumPy 超详细教程(3):ndarray 的内部机理及高级迭代 文章目录 NumPy 数据类型 ...

  10. Android中一个经典理解误区的剖析

    今天,在Q群中有网友(@广州-包晴天)发出了网上的一个相对经典的问题,问题具体见下图. 本来是无意写此文的,但群里多个网友热情不好推却,于是,撰此文予以分析. 从这个问题的陈述中,我们发现,提问者明显 ...