CLI的全称是Command-line Interface(命令行界面),即在命令行接受用户的键盘输入并作出响应和执行的程序。
在Node.js中,全局安装的包一般都具有命令行界面的功能,例如我们用于启动web服务的http-server包,在全局安装后,可按下图所示在当前目录启动一个web服务:
如果我们也想编写这样的命令行程序,该如何做呢?很简单,只需先创建下面这样的目录结构:
在bin目录中,我们创建了一个my-cli.js的文件,文件内容如下:
#!/usr/bin/env node console.log('hello my-cli');
注意:第一行非常重要,标记这是一个node环境可执行文件。
而图中的package.json的内容如下所示:
{ "author": "Mr.L", "license": "MIT", "name": "my-cli", "version": "1.0.0", "description": "my-cli", "bin": { "my-cli": "bin/my-cli.js" }, "preferGlobal": "true" }
在package.json文件中,我们指定了bin属性,其中的key就是命令行指令名称,映射到bin/my-cli.js这个可执行文件,最后的`preferGlobal`设置为`true`,表示可在全局安装并运行。
最后,在命令行进入图中的my-cli目录,执行如下命令:
如图所示,我们先执行`npm install -g .`命令,全局安装当前包,在安装完成后,直接在命令行执行`my-cli`,即可运行相关的程序。
到这里我们就完成了自己的一个简单CLI程序,不过通常来说,CLI程序需要一些实际的交互功能,并且最好能够支持两种运行方式:即命令行和作为普通包引入。
我们稍微修改一下上面的目录结构:
如图所示,我们新创建了一个lib目录,用于放置主要的业务逻辑,代码如下:
let chalk = require('chalk'); let sayHello = name => { // 使用chalk 设置控制台字体样式 return chalk.bold('Hello, ') + chalk.bold.bgRed(name); }; // 导出 exports.sayHello = sayHello;
我们定义了一个`sayHello`方法,根据传递的`name`参数,生成一个问候语,需要注意的是,我们在该文件中引入了`chalk`库,该库用于设置命令行的文字样式。
下面我们再来看看bin/my-cli.js文件的内容:
#!/usr/bin/env node let readline = require('readline'); let lib = require('../lib/index.js'); // 创建交互界面 let interface = readline.createInterface({ input: process.stdin, output: process.stdout }); // 开始界面交互 interface.question('What is your name? ', answer => { let greeting = lib.sayHello(answer); // 打印结果 console.log(greeting); interface.close(); });
在上面的代码中,我们引入Node.js内置的`realline`模块,该模块在标准输入和标准输出的基础上做了封装,在命令行中给出提示,并接受用户输入;另外,我们也引入了lib目录中的index.js,在接受用户输入后,调用`sayHello`方法,生成结果并打印。
最后,package.json也要相应做些修改:
{ "author": "Mr.L", "license": "MIT", "name": "my-cli", "version": "1.0.0", "description": "my-cli", "bin": { "my-cli": "bin/my-cli.js" }, "main": "lib/index.js", "preferGlobal": "true", "dependencies": { "chalk": "^1.1.3" } }
我们添加了一个`main`属性,指向lib/index.js文件,这样便于其他开发者在程序中引入,调用我们的`sayHello`方法,我们稍后会介绍。
现在我们再执行`npm install -g .`命令,全局安装当前包,然后打开新的命令行:
如图所示,该程序接受了命令行参数,并正确打印出了结果。
前面提到,我们的CLI也要作为一个普通包被开发者引入,现在我们就来演示一下。首先,创建一个测试目录,如下图所示:
这个目录很简单,只有一个test.js文件和一个node_modules目录,在node_modules目录中包含我们的my-cli目录:
我们简单看一下test.js文件的内容:
let cli = require('my-cli'); let greeting = cli.sayHello('Jack'); console.log(greeting);
然后,我们在命令行直接执行该文件,打印结果如下图所示:
最后,我们也可以将自己的库发布到npm仓库,按照官方文档指示即可完成。
参考资料:
https://bretkikehara.wordpress.com/2013/05/02/nodejs-creating-your-first-global-module