并非严格的教程博文,属于是个人在学习过程中的笔记心得汇总。
内容相对官方文档更通俗一些,入门新人,如果看不懂官方文档,可以大致看一看这个。有错的话请指正,标准的还得看官方文档。

1.commander.js概述

commander.js是一个工具,用来构建node的命令行程序,使得能够使用自定义指令在全局命令行运行node脚本

本来我们只能在脚本所在文件的根目录里通过node xxx.js运行脚本,通过commander构建命令行程序后,就能在任意一个目录里,比如桌面,比如用户目录,直接输入自定义的那个指令,就能直接运行脚本,更加简便。

另外还有一种简便的方式,就是打包成exe文件,直接双击就能运行,但是缺点在于适应性,就是如果想要在win、linux等多个平台使用,就得分别打包,而使用命令行形式,可以轻松跨平台使用

2.小案例演示

光说未必能想象出来,还得实际场景看一看,我这就写一个小小案例演示一下。
1.文件目录

├─bin
├─node_modules
│  └─commander
│      ├─lib
│      └─typings
└─src

除此之外还有package.json文件,上面图没有显示

2.文件内容

//index.js
console.log('演示案例');
#!/usr/bin/env node
//my-cli.js
const program=require('commander')
program.version('1.0.0').parse(process.argv)
require('../src/index.js')
{"name": "cac","version": "1.0.0","main": "index.js","license": "MIT","dependencies": {"commander": "^9.4.0"},"bin": {"my-cli":"./bin/my-cli.js"}
}

3.全局运行脚本

没有用node做前缀运行,没有在根目录,直接在全局cmd就直接运行了脚本,输出了结果,这就是commander的作用。

另外这个命令还能配置很多参数功能,如查看版本等,都可以自定义配置

4.实现方法
①功能写在主文件index.js里
②然后通过bin文件夹下的my-cli引入运行
③最后在package.json里配置bin字段,设置自定义命令文件路径
④在根目录使用yarn link/npm link,将软件包链接到全局

3.安装

npm安装:

npm install commander

yarn安装:

yarn add commander

4.声明program变量

commander提供了一个全局对象program

const program= require('commander');

如果要是用多种方式使用commander,可以通过Command类来创建

const {Command}=require('commander')
const program=new Command()

5.选项

选项定义

  • 使用.option()方法定义
  • 每个选项可以定义两个名字,一个短选项(-开头接单个字符),一个长选项(--开头接多个字符),逗号隔开(也可以用空格或者|
program.option('-a,--anli','这里是描述语句')

选项获取

  • 解析后的选项可以使用.opts()方法获取(选项同时也会传递给命令处理函数–不懂,待补充
  • 如果长选项的命名使用了多单词,比如max-length,就会自动被转化为驼峰命名法maxLength
  • 没有在命令行使用选项则选项值为undefined
program.option('-a,--anli','演示案例选项').option('-b,--tuo-feng','转化为驼峰命名').parse()
console.log('已经被解析的选项和选项值',program.opts());
console.log('可以直接通过选项名获取选项值:tuoFeng,',program.opts().anli,program.opts().tuoFeng);
PS F:\desk\cac> my-cli
已经被解析的选项和选项值 {}
可以直接通过选项名获取选项值:tuoFeng, undefined
PS F:\desk\cac> my-cli -a -b
已经被解析的选项和选项值 { anli: true, tuoFeng: true }
可以直接通过选项名获取选项值:tuoFeng, true

常用选项类型

  • 有两种,一类是boolean选项,无需配置参数,在命令行中不指定选项被定义为undefined,指定则为true
  • 另一类是带参数选项,在名字后面用尖括号声明,如--canshu <value>,在命令行不指定选项名被定义为undefined,指定选项但没有赋参数则会报错error: option '-a,--anli <value>' argument missing
  • 多个布尔值选项连写可以合并,如-a -b -c可以合并为为 -abc,也可以和一个带参数选项连写,带参数的放在最后如-abcp test
  • 带参数类型后如果没写参数,它会读取后面的选项作为参数,如 -a -b,最后a的参数值为‘-b’
program.option('-a,--anli <value>','带参数选项').option('-b,--boolean','布尔值选项').parse()
console.log('已经被解析的选项和选项值',program.opts());
PS F:\desk\cac> my-cli
已经被解析的选项和选项值 {}
PS F:\desk\cac> my-cli -a
error: option '-a,--anli <value>' argument missing
PS F:\desk\cac> my-cli -b
已经被解析的选项和选项值 { boolean: true }
PS F:\desk\cac> my-cli -b -a test
已经被解析的选项和选项值 { boolean: true, anli: 'test' }
PS F:\desk\cac> my-cli -a --boolean
已经被解析的选项和选项值 { anli: '--boolean' }

选项默认值

  • 带参数选项可以设置默认值,当在命令行没有指定选项时,自动赋默认值。
  • 指定选项但没有写参数,则还是会报错
  • 指定选项且写了参数,赋写的新参数
program.option('-a,--anli <value>','描述','moren').parse()
console.log('已经被解析的选项和选项值',program.opts());
PS F:\desk\cac> my-cli
已经被解析的选项和选项值 { anli: 'moren' }
PS F:\desk\cac> my-cli -a
error: option '-a,--anli <value>' argument missing
PS F:\desk\cac> my-cli -a qer
已经被解析的选项和选项值 { anli: 'qer' }
PS F:\desk\cac>

取反选项
是一个以no-开头的布尔值型长选项,作用是在命令行使用时,把选项值赋false
有如下几种情况

  • 只使用原选项,赋值为true
  • 只使用取反选项,赋值为false
  • 先使用原选项,后使用取反选项,赋值为false
  • 先使用取反选项,后使用原选项,赋值为true
  • 总的来说就是赋值可覆盖,以后者为准
program.option('-c,--cac','描述').option('--no-cac','取反选项').parse()
console.log('已经被解析的选项和选项值',program.opts());
PS F:\desk\cac> my-cli
已经被解析的选项和选项值 {}
PS F:\desk\cac> my-cli -c
已经被解析的选项和选项值 { cac: true }
PS F:\desk\cac> my-cli --no-cac
已经被解析的选项和选项值 { cac: false }
PS F:\desk\cac> my-cli -c --no-cac
已经被解析的选项和选项值 { cac: false }
PS F:\desk\cac> my-cli --no-cac -c
已经被解析的选项和选项值 { cac: true }

可选参数选项

  • 参数可选,在使用选项但没给参数的情况下会变成布尔值选项
  • 且不会像带参数选项那样把后面的选项命令当做参数,会忽略破折号开头的输入参数,如果想让破折号开头的作为参数,可以使用=,如-i=-5
  • 参数使用方括号声明--icon [value]
program.option('-c,--cac [value]','描述').parse()
console.log('已经被解析的选项和选项值',program.opts());
PS F:\desk\cac> my-cli
已经被解析的选项和选项值 {}
PS F:\desk\cac> my-cli -c
已经被解析的选项和选项值 { cac: true }
PS F:\desk\cac> my-cli -c ahh
已经被解析的选项和选项值 { cac: 'ahh' }
PS F:\desk\cac> my-cli -c -666
error: unknown option '-666'
PS F:\desk\cac> my-cli -c=-666
已经被解析的选项和选项值 { cac: '=-666' }

必填选项

  • 必填选项要么设置了默认值,要么在命令行必须输入选项,必须保证选项在解析时有赋值
  • 使用.requiredOption()设置
PS F:\desk\cac> my-cli
error: required option '-c,--cac <value>' not specified

变长参数选项

可以在命令行输入多个参数,解析后会以数组形式存储,在下一个选项之前的输入都会被当做变长参数

program.option('-c,--cac <value...>','描述').parse()
console.log('已经被解析的选项和选项值',program.opts());
PS F:\desk\cac> my-cli -c a b c 1 2 3
已经被解析的选项和选项值 { cac: [ 'a', 'b', 'c', '1', '2', '3' ] }

版本选项

  • .version(),设置版本,自己只用填写版本号,它是有默认选项的,为-V(大写),--version
  • 使用选项会输出当前版本号
PS F:\desk\cac> my-cli -V
1.0.0

构造选项

  • 上面的选项配置都是通过.option()添加,但是还用一种方式,采用new Option()方式构建
  • 优点在于能够做更加详细的配置,用得不多,这里不多说,需要的时候再查
program.addOption(new Option('-e,--erhen'.hideHelp()))

自定义选项处理
自定义一个函数,放置在选项中,当传入参数时会自动处理参数并返回结果
函数有两个参数,分别为新参数和老参数

function add(value,previous){return [value,previous]
}
program.version('1.0.0').option('-c,--cac <value...>','描述',add).parse()
console.log('已经被解析的选项和选项值',program.opts());
PS F:\desk\cac> my-cli -c 3
已经被解析的选项和选项值 { cac: [ '3', undefined ] }
PS F:\desk\cac> my-cli -c 2 -c 3
已经被解析的选项和选项值 { cac: [ '3', [ '2', undefined ] ] }

6.命令

配置方法有两种方式

一种使用.command()配置,一种使用.addCommand()配置

实现方式也有两种,

一种为命令行绑定处理函数,在内部写一个函数来处理数据,另一种是把命令写成可执行文件,实现方法写在了后面,点击跳转

使用.command()进行配置,直接添加,直接执行

const {Command}=require('commander')
const program=new Command()
program.command('add <one> [two]').description('描述').action((one,two)=>{console.log('one:',one,'two:',two);}).parse()
PS F:\desk\cac> my-cli 2 3
one: 2 two: 3

当然,如果为program配置了多个命令,就要附上命令名了

const {Command}=require('commander')
const program=new Command()
program.command('add <one> [two]').description('描述').action((one,two)=>{console.log('one:',one,'two:',two);})
program.command('dd <on> [tw]').description('描述').action((on,tw)=>{console.log('on:',on,'tw:',tw);})
program.parse()
PS F:\desk\cac> my-cli dd 2 3
on: 2 tw: 3

使用.addCommand()进行配置,采用了函数方式,执行也是函数名加子命令,相当于打了一个包。

const {Command}=require('commander')
function addcomm(){const addcom=new Command('addcom')addcom.command('asd').action(()=>{console.log('asdd');})addcom.command('asf').action(()=>{console.log('asdf');})return addcom
}program.addCommand(addcomm()).parse(process.argv)
PS F:\desk\cac> my-cli addcom asf
asdf

命令参数
上面命令的参数是直接在command里指定的,但是还有另一种方法,使用.argument()添加参数,command只写名称。

注意:一个argument里只能写一个参数,要想写多个参数得用arguments

使用argument

const {Command}=require('commander')
const program=new Command()
program.command('add').argument('<one>','参数描述').argument('<two>','参数描述').action((one,two)=>{console.log('one:',one,'two:',two);})
program.parse()

使用arguments

.arguments("<one>","[two]")

和选项一样,也能用可变参数,用法一样

.argument('<dirs...>')

同样的,也有自定义参数处理,老一套

.argument('<first>', 'integer argument', myParseInt)

处理函数

  • 处理函数就是上面提到过的.action(),通过命令传递参数后,使用函数做相应的处理。
  • 除了命令传递的参数外,处理函数还自带了两个参数,一个是options解析的选项,一个是command命令本身
  • 可以跳过参数声明直接使用command,使用关键字this操作,注意不能在箭头函数用
.action((one,two,options,command)=>{console.log('one:',one,'two:',two);
})
.action(function(){console.log(this.opts());
})

独立可执行命令

> - 如果command带有**参数描述**,就代表可以使用独立的可执行文件作为处理函数 > - commander就会在脚本根目录搜索`command-subcommand`类型文件,就比如,我的指令是`my-cli`,命令的名字是`add`,他就会去找`my-cli-add`文件去处理参数

program.command('add [name]','xxx')

看下面的报错,我执行了指令和命令,带上了参数,他就会去根目录找相应文件,但是这时候没有这个文件,就报错了
后面建立了该文件,就成功执行,输出了‘233’

PS F:\desk\cac> my-cli add 233
node:internal/modules/cjs/loader:936throw err;^Error: Cannot find module 'F:\desk\cac\my-cli-add'at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)at Function.Module._load (node:internal/modules/cjs/loader:778:27)at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)at node:internal/main/run_main_module:17:47 {code: 'MODULE_NOT_FOUND',requireStack: []
}
PS F:\desk\cac> my-cli add 233

生命周期钩子
和vue之类的一样,commander也有生命周期,设置回调函数就可以在对应的时机执行

钩子 触发时机 参数
preAction/postAction 本命令的处理函数执行前后 thisCommand,actionCommand
preSubcommand 直接子命令解析之前 thisCommand,subcommand
.hook('preAction',(thisCommand, actionCommand)=>{console.log('生命周期函数用法');
})

补充

.parse()
作用就是解析,参数就是要解析的字符串,一般使用时参数就是用process.argv,就是用户输入参数

(这些都是比较常用的部分,有一些功能可以去官方文档看,看不懂可以留言,我要是看得懂就在这补充上去)

commander.js教程笔记相关推荐

  1. Node.js之commander.js学习笔记

    概述 commander.js可以用来写命令行工具. 官网地址:Commander.js 安装与引入 安装 执行如下命令进行安装,但前提是有node环境,即能使用npm命令进行安装: npm inst ...

  2. 廖雪峰js教程笔记10 浏览器对象

    JavaScript可以获取浏览器提供的很多对象,并进行操作. window window对象不但充当全局作用域,而且表示浏览器窗口. window对象有innerWidth和innerHeight属 ...

  3. +pink老师的JS教程笔记+

    初识JS 目标 能够说出JS是什么 能够知道JS的发展历史 能够说出浏览器执行JS的原理 能够说出JS由哪三部分组成 能够写出JS三个输入输出的语句 运行在客户端的脚本语言(不需要编译,由js引擎逐行 ...

  4. html css廖雪峰,廖雪峰js教程笔记12 用DOM更新 innerHMTL 和修改css样式(示例代码)

    拿到一个DOM节点后,我们可以对它进行更新. 可以直接修改节点的文本,方法有两种: 一种是修改innerHTML属性,这个方式非常强大,不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段 ...

  5. 廖雪峰js教程笔记 2

    arguments JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数.arguments类似Array但它不是一个Arr ...

  6. 廖雪峰js教程笔记9 json

    JSON是JavaScript Object Notation的缩写,它是一种数据交换格式. 在JSON出现之前,大家一直用XML来传递数据.因为XML是一种纯文本格式,所以它适合在网络上交换数据.X ...

  7. 【JS学习笔记】基于自学的JavaScript学习笔记(1)JS教程与简介

    JavaScript学习目录 为什么要学习JS以及怎么学习 第一课时:JS教程与简介 1.什么是JavaScript? 2.JS定义: 3.JS作为脚本语言的特点 4.我能学习到什么? Sum Cha ...

  8. React.js入门笔记

    # React.js入门笔记 核心提示 这是本人学习react.js的第一篇入门笔记,估计也会是该系列涵盖内容最多的笔记,主要内容来自英文官方文档的快速上手部分和阮一峰博客教程.当然,还有我自己尝试的 ...

  9. prototype.js教程及prototype中文手册

    在线API文档:   http://www.prototypejs.org/api 1.4网页版: http://thinhunan.cnblogs.com/archive/2006/04/01/De ...

最新文章

  1. 网络流24题-飞行员配对方案问题
  2. mac网页转换pdf教程,在Mac系统中如何将html网页转成PDF文件?
  3. 为 Windows 用户准备的简明 Linux 词汇表
  4. git checkout远程分支_Git检出远程分支
  5. 在windows中使用scp命令将文件上传到远端服务器
  6. EditPlus安装及远程连接Linux
  7. 求小于100的所有合数 python_python100例
  8. 基于libVLC的视频播放器之五:抽帧
  9. canvas绘制五角星
  10. 2022-2028年中国粮食物流行业市场发展调研及未来前景规划报告
  11. matlab产生窄带信号,窄带信号
  12. python you-get库
  13. 42多功能高速闭环驱动器使用手册
  14. x264学习----x264.h结构体
  15. VS2015 密钥 专业版和企业版
  16. java微信分享朋友圈_java怎么实现微信分享到朋友圈功能
  17. 技术实践|Redis基础知识及集群搭建(上)
  18. 通过不断重置学习率来逃离局部极值点
  19. 1、IG夺冠,校长送钱
  20. 张瑞敏分享海尔变革实践:借鉴黄金圈法则 革自己的命

热门文章

  1. What is Spring Boot? Autoconfigurations In-Depth
  2. 苹果mini卖的有点惨。。。
  3. 常用URL Scheme
  4. 支付宝集成--基本操作1
  5. win10计算机不显示usb,Win10插入移动硬盘或U盘有提示声但电脑中不显示的解决方法...
  6. cesium实现淹没分析(基于polygon)并解决屏闪
  7. ResultSet相关ResultSetMetaData详细
  8. Web前端 | HTML引入CSS样式的三种方式
  9. Java 遍历treemap_TreeMap的两种遍历方式
  10. 阿姆斯特朗数。。。。