Nodejs how-to-write-a-node-cli-tools-with-commander
Nodejs how-to-write-a-node-cli-tools-with-commander
how-to-write-a-node-cli-tools
什么是cli tools?
CLI(command-line interface,命令行界面)是指可在用户提示符下键入可执行指令的界面。
早启的unix/linux和DOS都是没有可视化界面的,那内存靠计算着用的时代都只能玩玩命令。
node cli
好处
- 现在火,前端以及服务器端必备技能
- js语法,非常好写
- 对版本要求不像ruby那样苛刻
缺点,暂未知,看以后node的路吧
做法
创建git repo
git clone到本地
git clone git@github.com:i5ting/node-cli-demo.git
切换到项目目录
cd node-cli-demo
初始化npm
执行
npm init
一直回车,除非你真的有东西想改动,具体如下
➜ node-cli-demo git:(master) npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.
See npm help json
for definitive documentation on these fields
and exactly what they do.
Use npm install <pkg> --save
afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
name: (node-cli-demo)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository: (https://github.com/i5ting/node-cli-demo.git)
keywords:
author:
license: (ISC)
About to write to /Users/sang/workspace/github/node-cli-demo/package.json:
{
“name”: “node-cli-demo”,
“version”: “1.0.0”,
“description”: “node-cli-demo =============”,
“main”: “index.js”,
“scripts”: {
“test”: “echo “Error: no test specified” && exit 1”
},
“repository”: {
“type”: “git”,
“url”: “https://github.com/i5ting/node-cli-demo.git”
},
“author”: “”,
“license”: “ISC”,
“bugs”: {
“url”: “https://github.com/i5ting/node-cli-demo/issues”
},
“homepage”: “https://github.com/i5ting/node-cli-demo”
}
Is this ok? (yes)
➜ node-cli-demo git:(master) ✗
创建文件
mkdir bin
mkdir test
touch bin/node-cli-demo.js
touch test/node-cli-demo.js
touch index.js
touch gulpfile.js
修改package.json
命令配置(至关重要)
"preferGlobal": "true",
"bin": {
"badge": "bin/badge.js"
},
此处是关键
preferGlobal
确定你的这个命令是不是全局的,一定要设置为true,不然不放到path里,不能全局用的。
bin
是配置你的cli名称和具体哪个文件来执行这个的
依赖
"devDependencies": {
"chai": "^1.9.2",
"gulp": "^3.8.10",
"gulp-istanbul": "^0.3.1",
"gulp-mocha": "^1.1.1",
"istanbul": "^0.3.2",
"mocha": "^2.0.1",
"sinon": "^1.11.1",
"supertest": "^0.14.0",
"supervisor": "^0.6.0",
"zombie": "^2.1.1"
},
"dependencies": {
"commander": "^2.5.0",
"config": "^1.7.0",
"handlebars": "^2.0.0",
"request": "^2.47.0"
},
当前npm依赖dependencies
- commander (命令辅助lib)
- config (配置项)
- handlebars (模板操作)
- request (http请求库)
如果这些不够的话
npm install --save xxx
开发阶段的依赖devDependencies
- mocha(测试相关)
- gulp (项目构建相关的)
如果这些不够的话
npm install --save-dev xxx
scripts
"scripts": {
"start": "npm publish .",
"test": " node bin/badge.js -t js -n q "
},
这里定义了2个命令
npm start
这里我用它发布当前npm到npmjs.org上
npm test
这里我用它作为测试代码,避免每次都重复输入
修改 bin/node-cli-demo.js
#!/usr/bin/env node
/**
* Module dependencies.
*/
function isDefined(x) { return x !== null && x !== undefined; }
Array.prototype.contain = function(obj) {
return this.indexOf(obj) !== -1;
}
var program = require('commander');
var version = require("../package.json").version;
program
.version(version)
.usage(" badge -n badge-cli -f [md] -t [npm] ")
.option('-n, --name [name]', 'npm name,for example: q')
.option('-f, --format [format]', '可选值:url, markdown(默认值), html, textile, rdoc, asciidoc, rst')
.option('-t, --type [type]', '可选值:npm(默认值), ruby , python , bower , github , nuget , php , cocoapods , perl ')
.option('-v, --verbose', '打印详细日志')
.parse(process.argv);
var module_name = '';
if(isDefined(program.name) == true && typeof program.name == 'string' ){
module_name = program.name;
}else{
console.log('没有知道模块名称,请重新输入,比如\n\t badge -n badge-cli -f [md] -t [npm] ');
return;
}
var format = "markdown";
var type = "js";
if (program.format) {
format = program.format;
}
if (program.type) {
type = program.type;
}
var verbose = false;
if (program.verbose) {
verbose = program.verbose;
}
var FORMATS = ['url', 'markdown', 'html', 'textile', 'rdoc', 'asciidoc', 'rst']
if (FORMATS.contain(format) == false) {
console.log('-f 可选值:url, markdown(默认值), html, textile, rdoc, asciidoc, rst');
return;
}
var _verbose = verbose;
function log(str){
if(_verbose == true){
console.log(str);
}
}
log('format = ' + format);
log('type = ' + type);
log('name = ' + module_name);
log('verbose = ' + verbose);
// main
// require('../index')(module_name, type, format, verbose);
注意
- shabang用法
#!/usr/bin/env node
- commander用法
var program = require('commander');
var version = require("../package.json").version;
program
.version(version)
.usage(" badge -n badge-cli -f [md] -t [npm] ")
.option('-n, --name [name]', 'npm name,for example: q')
.option('-f, --format [format]', '可选值:url, markdown(默认值), html, textile, rdoc, asciidoc, rst')
.option('-t, --type [type]', '可选值:npm(默认值), ruby , python , bower , github , nuget , php , cocoapods , perl ')
.option('-v, --verbose', '打印详细日志')
.parse(process.argv);
还是比较简单的
- 参数的默认值
var module_name = '';
if(isDefined(program.name) == true && typeof program.name == 'string' ){
module_name = program.name;
}else{
console.log('没有知道模块名称,请重新输入,比如\n\t badge -n badge-cli -f [md] -t [npm] ');
return;
}
- 主文件
// main
require('../index')(module_name, type, format, verbose);
注意主文件参数按需求定义
编写index.js
module.exports = function (module_name, type, format,verbose) {
console.log('i am main file for cli');
}
编写test/node-cli-demo.js
var assert = require('chai').assert;
var expect = require('chai').expect;
require('chai').should();
describe(‘Node-cli-demo’, function(){
before(function() {
// runs before all tests in this block
})
after(function(){
// runs after all tests in this block
})
beforeEach(function(){
// runs before each test in this block
})
afterEach(function(){
// runs after each test in this block
})
describe(’#save()’, function(){
it(‘should return test2 when user save’, function(){
assert.equal(1, 1);
})
})
})
增加自动测试和代码覆盖率
修改gulpfile.js
var gulp = require('gulp');
var istanbul = require('gulp-istanbul');
var mocha = require('gulp-mocha');
gulp.task('test', function (cb) {
gulp.src(['db/**/*.js'])
.pipe(istanbul()) // Covering files
.on('finish', function () {
gulp.src(['test/*.js'])
.pipe(mocha({
ui : 'bdd',
reporter: 'spec'
}))
.pipe(istanbul.writeReports()) // Creating the reports after tests runned
.on('end', cb);
});
});
gulp.task('default',['test'], function() {
gulp.watch(['./db/**/*','./test/**/*'], ['test']);
});
gulp.task('watch',['test'], function() {
gulp.watch(['./db/**/*','./test/**/*'], ['test']);
});
注意自己修改目录
- src目录
- 测试目录
测试
node_modules/.bin/gulp
这时,你试试修改测试或源文件试试,看看会不会自动触发测试
当然,如果你喜欢只是测试一次,可以这样做
node_modules/.bin/gulp test
如果你不熟悉gulp,可以再这里https://github.com/i5ting/js-tools-best-practice/blob/master/doc/Gulp.md学习
发布
npm start
技术
- https://github.com/tj/commander.js(命令行)
- https://github.com/request/request(http请求)
- https://github.com/mochajs/mocha(测试)
- https://github.com/wycats/handlebars.js(模板)
- https://github.com/lorenwest/node-config (配置)
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
推荐
版本历史
- v0.1.0 初始化版本
欢迎fork和反馈
- write by
i5ting
shiren1118@126.com
如有建议或意见,请在issue提问或邮件
License
this repo is released under the MIT License.
欢迎关注我的公众号【node全栈】
demo 位置https://github.com/i5ting/node-cli-demo
推荐更好的写法
https://github.com/montagejs/minit/blob/master/cli.js
var fs = require("fs");
var path = require("path");
var Command = require(“commander”).Command;
var config = require("./package.json");
var create = require("./lib/create");
var serve = require("./lib/serve");
var cli = new Command();
//extras
cli.minitHome = __dirname + “/”;
//
cli.version(config.version);
create.addCommandsTo(cli);
var serveCommand = cli.command(‘serve’)
.description(‘serve current directory with minit server.’)
.action(function(env){
serve.serve(env);
});
serve.addOptions(serveCommand);
exports.command = cli;
视频http://haoqicat.com/shiren1118/nodejs/1
针对“Nodejs how-to-write-a-node-cli-tools-with-commander”这个主题,下面将详细介绍如何使用Node.js结合commander
库来编写一个命令行工具。
步骤概述
- 初始化项目:使用
npm init
生成package.json
。 - 安装依赖:安装必要的依赖包如
commander
。 - 创建入口文件:在项目中创建入口文件,用于定义CLI的行为。
- 配置bin路径:在
package.json
中配置bin路径,以便命令行工具可以通过命令直接调用。 - 实现逻辑:在入口文件中实现命令行工具的功能。
- 测试与发布:编写测试用例,并通过
npm start
发布工具。
示例代码
1. 初始化项目
mkdir node-cli-demo
cd node-cli-demo
npm init -y
2. 安装依赖
npm install commander --save
3. 创建入口文件
在bin
目录下创建node-cli-demo.js
:
#!/usr/bin/env node
const program = require('commander');
program
.version('1.0.0')
.description('A simple CLI tool')
.option('-m, --message [value]', 'Your custom message')
.parse(process.argv);
console.log(`Your message: ${program.message || 'No message provided.'}`);
4. 配置package.json
{
"name": "node-cli-demo",
"version": "1.0.0",
"description": "A simple CLI tool",
"main": "index.js",
"bin": {
"node-cli-demo": "bin/node-cli-demo.js"
},
"scripts": {
"start": "npm publish .",
"test": "node bin/node-cli-demo.js -m 'Test message'"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"chai": "^1.9.2",
"mocha": "^2.0.1"
},
"dependencies": {
"commander": "^2.5.0"
}
}
5. 实现逻辑
入口文件bin/node-cli-demo.js
已包含基本的CLI逻辑。
6. 测试与发布
npm test
npm start
总结
以上步骤展示了如何使用Node.js和commander
库创建一个简单的命令行工具。此工具接受一个可选的--message
参数并输出消息。你可以根据需要扩展更多功能和参数。