文章目录
前言
如何手动写一个命令行甚至说发布一个npm包,这涉及到所需要提供服务的接口和优雅的命令行外观,本文将分为两部分去介绍构建命令行工具的方法。
提示:以下是本篇文章正文内容,下面案例可供参考
一、一个最简单的命令行工具
如何在命令行中输入一条命令,使它返回一句话?
首先我们需要建立一个文件夹,并在文件夹中npm init
,建立一个index.js
文件,在该文件中编写主要逻辑代码。
#!/usr/bin/env node
console.log('hello,world!')
/usr/bin/env就是告诉系统可以在PATH目录中查找。 所以配置#!/usr/bin/env node, 就是解决了不同的用户node路径不同的问题,可以让系统动态的去查找node来执行你的脚本文件。
要不要加–harmony?
文档里这么说,windows下不支持这么做。这个写法一般用于一些子命令的脚本中。
Use #! /usr/bin/env node --harmony in the subcommands scripts. (Note Windows does not support this pattern.)
Use the --harmony option when call the command, like node --harmony examples/pm publish. The --harmony option will be preserved when spawning subcommand process.
修改package.json
{
"name": "mycli",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"bin":{
"hi":"./index.js"
},
"license": "ISC"
}
二、命令行解析工具
1.commander
文档地址:https://www.npmjs.com/package/commander
(1)option
Options are defined with the .option() method, also serving as documentation for the options. Each option can have a short flag (single character) and a long name, separated by a comma or space or vertical bar (’|’).
意思是可以这么使用options的第一个参数,简写和完整形式之间可以用逗号,空格和‘|’连接。
program
.option('-u, --username <username>', 'The user to authenticate as')
The two most used option types are a boolean option, and an option which takes its value from the following argument (declared with angle brackets like --expect ). Both are undefined unless specified on command line.
如果没有传参每个option返回的是一个布尔值,用于判断该option是否被执行;如果有传参,在定义时需要加上<>来进行参数传递。
The parsed options can be accessed by calling .opts() on a Command object, and are passed to the action handler. Multi-word options such as “–template-engine” are camel-cased, becoming program.opts().templateEngine etc.
如这段代码所示调用program的opts()
方法可以对options进行一些逻辑判断,从而给每个option不同的方法,注意option如果碰到一长串字符的选项会自动变成驼峰命名,在opt方法中调用参数的话,需要用模板字符串来返回。
var co = require('co');
var prompt = require('co-prompt');
var program = require('commander');
program
.option('-d, --debug', 'output extra debugging')
.option('-s, --small', 'small pizza size')
.option('-p, --pizza-type <type>', 'flavour of pizza');
program.parse(process.argv);
const options = program.opts();
if (options.debug) console.log(options);
console.log('pizza details:');
if (options.small) console.log('- small pizza size');
if (options.pizzaType) console.log(`- ${options.pizzaType}`);
如果没有设置默认值的话,控制台会返回这样的结果,C:\Users\15905\mycli>hi -p error: option '-p, --pizza-type <type>' argument missing
,所以我们可以在option里面增加参数,使得他有一个默认的返回值。
program
.option('-c, --cheese <type>', 'add the specified type of cheese', 'blue');
program.parse();
console.log(`cheese: ${program.opts().cheese}`);
增加一些option
program
.addOption(new Option('-s, --secret').hideHelp())
.addOption(new Option('-t, --timeout <delay>', 'timeout in seconds').default(60, 'one minute'))
.addOption(new Option('-d, --drink <size>', 'drink size').choices(['small', 'medium', 'large']));
也可以在action中对options进行判断
program
.arguments('<name>')
.option('-t, --title <honorific>', 'title to use before name')
.option('-d, --debug', 'display some debugging')
.action((name, options, command) => {
if (options.debug) {
console.error('Called %s with options %o', command.name(), options);
}
const title = options.title ? `${options.title} ` : '';
console.log(`Thank-you ${title}${name}`);
});
(2)version
program.version('0.0.1');
(3)command
和-option有些像,可以将它的参数传入action,因此逻辑可以在action里面处理。
如果和-option卸载一个段落,option会作为他的子命令出现。
program
.command('clone <source> [destination]')
.description('clone a repository into a newly created directory')
.action((source, destination) => {
console.log('clone command called');
});
program.parse();
(4)argument
在当前command下添加传入参数,假设有两个参数,一个是username,另外一个是password,第一个参数是必须要填的(否则不能判断第二个参数是那个),第二个参数可不填且有默认值。
program
.version('0.1.0')
.arguments('<username> [password]')
.description('test command', {
username: 'user to login',
password: 'password for user, if required'
})
.action((username, password) => {
console.log('username:', username);
console.log('environment:', password || 'no password given');
});
program.parse()
输出如下
C:\Users\15905\mycli>hi
error: missing required argument 'username'
C:\Users\15905\mycli>hi 'mouziyao' '123456'
username: 'mouziyao'
environment: '123456'
C:\Users\15905\mycli>hi 'mouziyao'
username: 'mouziyao'
environment: no password given
C:\Users\15905\mycli>
2.co-prompt
文档地址:https://www.npmjs.com/package/co-prompt
通过这个依赖更好的实现了登录逻辑,异步获得了账户名和密码,prompt和prompt.password API可以调用并返回值,password提供了不显示具体数字的功能。
#!/usr/bin/env node
var co = require('co');
var prompt = require('co-prompt');
var program = require('commander');
program
.version('0.0.2')
.arguments('<file>')
.option('-u, --username <username>', 'The user to authenticate as')
.option('-p, --password <password>', 'The user\'s password')
.action(function(file){
co(function *(){
var username = yield prompt('username: ');
var password = yield prompt.password('password: ');
console.log('user: %s password: %s file: %s',
username, password, file);
});
})
.parse(process.argv);
三、命令行美化提示依赖
1.readline
2.chalk
3.figlet
四、发布一个npm包
1、执行get registry
npm config get registry https://registry.npm.taobao.org/
2、配置本地仓库
npm config set registry=http://registry.npmjs.org
3、执行npm adduser
4、执行npm publish
5、执行成功
在npm官网的个人资料中能查看到发布的包
6、最后记得将本地仓库还原
npm config set registry=https://registry.npm.taobao.org/
总结
以上是手写命令行工具和发布的流程,对文档进行了一点解读,也动手制作了一个npm包,仅作参考。