前端架构: 脚手架框架之commander从基础到高级应用教程

commander


1 )概述

  • commander 是一个更为知名的脚手架框架
  • 进入它的npm官网: https://www.npmjs.com/package/commander
  • 目前版本: 12.0.0
  • Weekly Downloads 133,822,797 (动态数据)
  • 最近更新:15 days ago (npm)
  • 说明这是一个更优质的库
  • 同时使用commander的案例也更为知名:vue-cli,webpack-cli,create-react-app
  • 所以commander是我们开发脚手架过程中首选的框架

2 )快速实现一个 commander 脚手架

  • 仍旧在 xyzcli 这个脚手架项目之下,之前是使用 yargs, 这时候把 bin/index.js 修改成 bin/yargs.js (用于备份)
  • 进行安装 $ npm i commander -S
  • 新建 bin/index.js 并编写
    #!/usr/bin/env nodeconst pkg = require('../package.json')
    const commander = require('commander');
    // const { program } = commander; // 脚手架实例 program是一个单例
    const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program.version(pkg.version) // 设定版本.parse(process.argv) // 解析所有参数
    
  • 执行 $ xyzcli --version, 并查看结果
    1.0.0
    
  • 执行 $ xyzcli --help, 并查看结果
    Usage: xyzcli [options]Options:-V, --version  output the version number-h, --help     display help for command
    
  • 这时候,使用 commander 完成了最小粒度的脚手架
  • 这时候,可见,-V, -h 这种别名短称都已经默认给出了

3 )commander 通用全局配置

3.1 配置 usage

const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program.usage('<command> [option]').version(pkg.version) // 设定版本.parse(process.argv) // 解析所有参数
  • 执行 $ xyzcli -h, 查看输出
    Usage: xyzcli <command> [option]Options:-V, --version  output the version number-h, --help     display help for command
    
    • 可以看到 Usage: xyzcli <command> [option]

3.2 配置 name

const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program.name(pkg.name).usage('<command> [option]').version(pkg.version) // 设定版本.parse(process.argv) // 解析所有参数
  • 这里修改下 package.json 中的 name,比如修改成 xyzcli111

  • 执行 $ xyzcli -h, 查看输出

    Usage: xyzcli111 <command> [option]Options:-V, --version  output the version number-h, --help     display help for command
    
    • 注意这里的,Usage: xyzcli111 <command> [option] 变成了 xyzcli111
    • 验证完成,将 package.json 中的 name 从 xyzcli111 再修改回 xyzcli
  • 在实际应用中,我们会取 bin 属性中的第一个key (一般而言,bin里的配置和包名一致, 但是最好取bin的第一个key值)

    const program = new commander.Command();program// .name(pkg.name).name(Object.keys(pkg.bin)[0]) // 注意这里.usage('<command> [option]').version(pkg.version) // 设定版本.parse(process.argv) // 解析所有参数
    
  • 这里不做输出测试

3.3 配置 option

const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program// .name(pkg.name).name(Object.keys(pkg.bin)[0]).usage('<command> [option]').version(pkg.version) // 设定版本.option('-f, --first', '第一个').option('-s, --separator <char>', '使用分隔符分割', ',').option('-d, --debug', '开启调试模式', false).option('-e, --envName <envName>', '获取环境变量名称').parse(process.argv) // 解析所有参数
  • 执行 $ xyzcli -h, 查看输出
    Usage: xyzcli <command> [option]Options:-V, --version            output the version number-f, --first              第一个-s, --separator <char>   使用分隔符分割 (default: ",")-d, --debug              开启调试模式 (default: false)-e, --envName <envName>  获取环境变量名称-h, --help               display help for command
    
  • 对参数进行解析和判断处理
    const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program// .name(pkg.name).name(Object.keys(pkg.bin)[0]).usage('<command> [option]').version(pkg.version) // 设定版本.option('-f, --first', '第一个') // 选择第一个参数.option('-s, --separator <char>', '使用分隔符分割', ',').option('-d, --debug', '开启调试模式', false).option('-e, --envName <envName>', '获取环境变量名称').parse(process.argv) // 解析所有参数const options = program.opts(); // 获取所有可用的 opt 作为参数
    const limit = options.first ? 1 : undefined; // 存在第一个参数, 则选1,不存在则不定义
    console.log(program.args[0].split(options.separator, limit)); // 基于分隔符分割获取参数
    
  • 执行,$ xyzcli -f x,y,z,查看输出结果
    [ 'x' ]
    
  • 执行,$ xyzcli -s / -f o/p/q, 查看输出结果
    [ 'o' ]
    

4 ) 配置 command 命令

  • 大类上还分两种小类型
    • 调用 command api 注册命令
    • 调用 addCommand api 注册命令

4.1 command

const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program// .name(pkg.name).name(Object.keys(pkg.bin)[0]).usage('<command> [option]').version(pkg.version) // 设定版本.option('-f, --first', '第一个') // 选择第一个参数.option('-s, --separator <char>', '使用分隔符分割', ',').option('-d, --debug', '开启调试模式', false).option('-e, --envName <envName>', '获取环境变量名称')// 定义一个克隆的命令
const clone = program.command('clone');
clone.description('克隆仓库').action(() => {console.log('do clone');});program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
  • 直接执行 $ xyzcli, 并输出
    Usage: xyzcli <command> [option]Options:-V, --version            output the version number-f, --first              第一个-s, --separator <char>   使用分隔符分割 (default: ",")-d, --debug              开启调试模式 (default: false)-e, --envName <envName>  获取环境变量名称-h, --help               display help for commandCommands:clone                    克隆仓库help [command]           display help for command
    
    • 这里可以看到存在两个 command: clone 和 help
  • 执行 $ xyzcli clone -h, 并输出
    Usage: xyzcli clone [options]克隆仓库Options:-h, --help  display help for command
    
  • 执行 $ xyzcli clone, 并输出
    do clone
    
  • 对 clone 命令进行扩展
    // 定义一个克隆的命令
    const clone = program.command('clone <source> [destination]');
    clone.description('克隆仓库').action((source, destination) => {console.log('do clone: ', source, destination);});program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli clone, 并输出
    error: missing required argument 'source'
    
    • 可见source是必传项
    • 而 destination 是可选项
  • 执行 $ xyzcli clone ss dd, 并输出
    do clone:  ss dd
    
  • 在clone命令中添加针对该命令的option
    // 定义一个克隆的命令
    const clone = program.command('clone <source> [destination]');
    clone.description('克隆仓库').option('--fc, --force', '是否强制克隆', false).action((source, destination, cmdObj) => {console.log('do clone: ', source, destination, cmdObj.force);});program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli clone ss dd, 并输出
    do clone:  ss dd false
    
  • 执行 $ xyzcli clone ss dd --fc, 并输出
    do clone:  ss dd true
    
    • 注意,这里简称不能与前面定义的冲突,如果是多个字符,用 --, 不能用一个 -
    • 这里 --fc--force
  • 执行 $ xyzcli clone --force ss dd, 并输出
    do clone:  ss dd true
    
    • 注意这里更换了option的位置,只要在 clone 后面,就不会受到影响

4.2 addCommand

  • addCommand 的特殊之处是可以注册子命令
    // 定义service脚手架
    const service = new commander.Command('service');
    service.command('start [port]').description('start service at some port').action((port) => {console.log('service port @', port)})program.addCommand(service);
    program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli -h, 查看输出
    Usage: xyzcli <command> [option]Options:-V, --version                           output the version number-f, --first                             第一个-s, --separator <char>                  使用分隔符分割 (default: ",")-d, --debug                             开启调试模式 (default: false)-e, --envName <envName>                 获取环境变量名称-h, --help                              display help for commandCommands:clone [options] <source> [destination]  克隆仓库servicehelp [command]                          display help for command
    
  • 执行 $ xyzcli service -h, 查看输出
    Usage: xyzcli service [options] [command]Options:-h, --help      display help for commandCommands:start [port]    start service at some porthelp [command]  display help for command
    
    • 这里看到 service 命令下存在一个子命令 start
  • 可以看到,这种方式可以对命令进行分组,比如在 service 下 有start, 还可以有stop
    // 定义service脚手架
    const service = new commander.Command('service');
    service.command('start [port]').description('start service at some port').action((port) => {console.log('service port @', port)})service.command('stop').description('stop service').action((port) => {console.log('stop service')})program.addCommand(service);
    program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli service -h, 查看输出
    Usage: xyzcli service [options] [command]Options:-h, --help      display help for commandCommands:start [port]    start service at some portstop            stop servicehelp [command]  display help for command
    
  • 执行 $ xyzcli service stop, 查看输出
    stop service
    
  • 通过子命令功能可大大扩展脚手架功能
  • 注意,分组下的 子命令必须如上分开写,不能连写

4.3 )对命令注册进行自动匹配

  • 可以通过 program.arguments 来监听所有命令输入
  • 除了上面注册的命令,其他命令都会命中这里的 arguments 中
    // 命令匹配
    program.arguments('<cmd> [options]').description('test command').action((cmd, options)=> {console.log(cmd, options);})program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli test, 查看输出
    test undefined
    
  • 执行 $ xyzcli, 查看输出
    error: missing required argument 'cmd'
    
    • 可以看到,这里 cmd 是要求强制输入的
  • 执行 $ xyzcli tt ss, 查看输出
    tt ss
    
  • 执行 $ xyzcli -h, 查看输出
    Usage: xyzcli <command> [option]test commandOptions:-V, --version                           output the version number-f, --first                             第一个-s, --separator <char>                  使用分隔符分割 (default: ",")-d, --debug                             开启调试模式 (default: false)-e, --envName <envName>                 获取环境变量名称-h, --help                              display help for commandCommands:clone [options] <source> [destination]  克隆仓库service
    
    • 可以看到这里没有什么信息,只有 一个 test command 的描述
  • 执行 $ xyzcli test -h, 同样也看不到其他实用的信息
  • 现在,对其再次进行修改,测试
    // 命令匹配
    program.arguments('<cmd> [options]').description('test command', {cmd: 'command to run',options: 'options for command'}).action((cmd, env)=> {console.log(cmd, env);})program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli test -h, 查看输出结果
    Usage: xyzcli <command> [option]test commandArguments:cmd                                     command to runoptions                                 options for commandOptions:-V, --version                           output the version number-f, --first                             第一个-s, --separator <char>                  使用分隔符分割 (default: ",")-d, --debug                             开启调试模式 (default: false)-e, --envName <envName>                 获取环境变量名称-h, --help                              display help for commandCommands:clone [options] <source> [destination]  克隆仓库service
    
  • 可以看到,这里多了 Arguments 这一项,里面的描述配置都有说明
  • 它的强大之处在于,可以匹配到所有输入的命令, 同时强制必须传 cmd 命令
  • 这个功能和在yargs框架中的 demandCommand 功能类似
  • 还有一种方式,也同样强大,如下
    program.command('install [name]', 'install package')program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli -h, 查看输出结果
    Usage: xyzcli <command> [option]test commandArguments:cmd                                     command to runoptions                                 options for commandOptions:-V, --version                           output the version number-f, --first                             第一个-s, --separator <char>                  使用分隔符分割 (default: ",")-d, --debug                             开启调试模式 (default: false)-e, --envName <envName>                 获取环境变量名称-h, --help                              display help for commandCommands:clone [options] <source> [destination]  克隆仓库serviceinstall [name]                          install package
    
    • 可以看到,最后的 install
  • 如果执行 $ xyzcli install -h, 查看发现报错
    • 报错信息为:Error: 'xyzcli-install' does not exist
    • 它会把当前脚手架 xyzcli 加上 -install 组成一个新的命令 xyzcli-install
    • 而这个命令在我们电脑上是没有的
    • 这个命令有些像 $ npm init install 当输入这个方法的时候也会报错
    • 它会告诉你,'create-install@latest' is not in the npm registry.
    • 这是因为,npm init 命令后面加上参数时,比如 加上 abc, 就是 npm init abc
    • 默认会在前面加上 create, 然后找这个包,也就是 create-abc 这个包
    • 如果这个包存在,则动态下载并执行这个包, 这块了解即可
  • 还可以加上别名
    program.command('install [name]', 'install package').alias('i')program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 执行 $ xyzcli -h, 查看输出结果
    Usage: xyzcli <command> [option]test commandArguments:cmd                                     command to runoptions                                 options for commandOptions:-V, --version                           output the version number-f, --first                             第一个-s, --separator <char>                  使用分隔符分割 (default: ",")-d, --debug                             开启调试模式 (default: false)-e, --envName <envName>                 获取环境变量名称-h, --help                              display help for commandCommands:clone [options] <source> [destination]  克隆仓库serviceinstall|i [name]                        install package
    
    • 可以看到上述别名起作用了
  • 同时,还可以添加第三个options参数
    program.command('install [name]', 'install package', {executableFile: 'npm', // 手动修改可执行文件}).alias('i')program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
  • 这时候我们执行 $ xyzcli i i vue -S
    • 这里的 xyzcli i 或 xyzcli install 等价于 npm
    • 所以,这时候,xyzcli i i vue -S 等价于 npm i vue -S
    • 执行后,可见 package.json 中存在了 vue
    • 这里很奇怪的是: 两个 i, 但是这个问题不大
  • 还有一些其他的配置,比如:
    program.command('install [name]', 'install package', {executableFile: 'npm', // 手动修改可执行文件isDefault: true, // 默认会匹配这个// hidden: true, // 不再帮助信息中显示}).alias('i')program.parse(process.argv) // 解析所有参数, 注意这里的调用位置
    
    • 这里 isDefault 设置为 true时,当执行 $ xyzcli 就直接会匹配到 npm 命令的帮助信息
    • 这里 hidden 设置为 true时,在帮助信息中就看不到 install 命令了

全部example参考

#!/usr/bin/env nodeconst pkg = require('../package.json')
const commander = require('commander');
// const { program } = commander; // 脚手架实例 program是一个单例
const program = new commander.Command(); // 这种手动实例化单例,同上,二取一program// .name(pkg.name).name(Object.keys(pkg.bin)[0]).usage('<command> [option]').version(pkg.version) // 设定版本.option('-f, --first', '第一个') // 选择第一个参数.option('-s, --separator <char>', '使用分隔符分割', ',').option('-d, --debug', '开启调试模式', false).option('-e, --envName <envName>', '获取环境变量名称')// 定义一个克隆的命令
const clone = program.command('clone <source> [destination]');
clone.description('克隆仓库').option('--fc, --force', '是否强制克隆', false).action((source, destination, cmdObj) => {console.log('do clone: ', source, destination, cmdObj.force);});// 定义service脚手架
const service = new commander.Command('service');
service.command('start [port]').description('start service at some port').action((port) => {console.log('service port @', port)})service.command('stop').description('stop service').action((port) => {console.log('stop service')})program.addCommand(service);// 设定 install 命令
program.command('install [name]', 'install package', {executableFile: 'npm', // 手动修改可执行文件// isDefault: true,// hidden: true,}).alias('i')// 命令匹配,用于兜底
program.arguments('<cmd> [options]').description('test command', {cmd: 'command to run',options: 'options for command'}).action((cmd, env)=> {console.log(cmd, env);	})program.parse(process.argv) // 解析所有参数, 注意这里的调用位置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/691392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker Desktop 链接windos 安装的redis和mysql

1.1.先在容器安装项目 2.链接redis和mysql配置 redis和mysql是在windos安装的&#xff0c;使用的是小p管理器安装的 项目链接 DB_DRIVERmysql DB_HOSThost.docker.internal DB_PORT3306 DB_DATABASEyunxc_test DB_USERNAMEyunxc_test DB_PASSWORDtest123456... DB_CHARSETutf…

Python中*args 和**kwargs

当函数的参数不确定时&#xff0c;可以使用*args 和**kwargs&#xff0c;*args 没有key值&#xff0c;**kwargs有key值。 *args [python] def fun_var_args(farg, *args): print "arg:", farg for value in args: print "another arg:", value fun_var_a…

Day10-Linux系统打包和时间命令及案例精讲

Day10-Linux系统打包和时间命令及案例精讲 1. tar 打包压缩1.1 【打包】 为什么要打包&#xff0c;压缩&#xff1f;1.2 【查看包里内容】1.3 【解包】1.4 排除打包 --exclude 2. date 时间命令 1. tar 打包压缩 1.1 【打包】 为什么要打包&#xff0c;压缩&#xff1f; -zcv…

一周学会Django5 Python Web开发-Django5路由变量

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计22条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

SPSSAU【文本分析】|文本聚类

SPSSAU共提供两种文本聚类方式&#xff0c;分别是按词聚类和按行聚类。按词聚类是指将需要分析的关键词进行聚类分析&#xff0c;并且进行可视化展示&#xff0c;即针对关键词进行聚类&#xff0c;此处关键词可以自由选择。按行聚类分析是指针对以‘行’为单位进行聚类分析&…

YOLOv8推理程序

YOLOv8单独推理,有时候我们自定义的模块算子无法正常转换为其他框架,而且需要做成应用,因此需要一个单独推理的程序,返回的是识别后的照片还有各个类别及其对应数量。文章最后给出Flask封装为Server以及调用的实例还有Client请求代码,支持几十路多线程并发,只需加载一次模…

闲鱼搜索API接口

闲鱼搜索API接口接口api代码对接如下&#xff1a; 1.公共参数 名称 类型 必须 描述 key String √ get请求方式拼接在url中&#xff0c;点击获取 api_name String √ api接口名称 cache String 默认否 result_type String 否 json lang String 默认cn 简…

linux部署jenkins,支持jdk1.8

无废话&#xff0c;纯干活安装指令 本文前提条件需安装jdk8&#xff0c;安装参考&#xff1a;Linux配置jdk环境 下载资源 # 创建安装目录 mkdir -p /data/jenkins && cd /data/jenkins# 下载jenkins的war包&#xff0c;v2.346.x支持jdk1.8&#xff0c;高于这个版本的…

【数据结构】图的最小生成树

最小生成树 一个图中有N个顶点&#xff0c;边的数量一定是>N-1&#xff0c;我们从中选取N-1条边&#xff0c;用来连接N个点&#xff0c;所形成的边权之和最小&#xff0c;就是最小生成树。 构成最小生成树的准则 只能使用图中的边来构造最小生成树只能使用恰好n-1条边来连…

Stable Diffusion 绘画入门教程(webui)-提示词

通过上一篇文章大家应该已经掌握了sd的使用流程&#xff0c;本篇文章重点讲一下提示词应该如何写 AI绘画本身就是通过我们写一些提示词&#xff0c;然后生成对应的画面&#xff0c;所以提示词的重要性不言而喻。 要想生成更加符合自己脑海里画面的图片&#xff0c;就尽量按照…

术业有专攻!三防加固平板助力工业起飞

在日常使用中的商业电脑比较追求时效性&#xff0c;以市场定位做标准&#xff0c;内部元件只需满足一般要求就行&#xff0c;使用寿命比较短。而三防平板电脑是主要运用在复杂、恶劣的环境下所以在需求方面较高,需要保证产品在恶劣条件下正常使用&#xff0c;满足行业领域的需求…

【CCEdit】通过扩散模型进行创意且可控的视频编辑

文章目录 CCEdit1. 核心特性1.1 三叉戟网络结构1.2 精细的外观控制1.3 高度的自适应性 2. 三叉戟结构2.1 结构分支&#xff08;ControlNet架构&#xff09;2.2 外观分支2.3 主分支 3. 数据集——BalanceCC benchmark dataset4. 训练5. 长视频编辑6. 使用场景7. 评估指标 CCEdit…

单片机01天---stm32基本信息了解

下载数据手册 以STM32F407ZG为例 网站&#xff1a;www.st.com&#xff0c;搜索芯片型号&#xff0c;下载“数据手册”使用 数据手册使用 查看芯片型号信息 芯片资源信息 时钟框图 芯片资源表格下方 GPIO口表格 一般位于下图后面的位置 ①工作电压&#xff1a;1.8V – 3.6V…

Codeforces Round 928 (Div. 4) (A-E)

比赛地址 : https://codeforces.com/contest/1926 A 遍历每一个字符串&#xff0c;比较1和0的数量即可&#xff0c;那个大输出那个; #include<bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define endl \n #define lowbit(x) (x&am…

C++BST(二叉搜索树)应用场景

CBST可以应用于各种场景&#xff1a; 数据的快速查找&#xff1a;由于BST的特性&#xff0c;可以很方便地进行查找操作。在BST中&#xff0c;查找一个特定元素的时间复杂度为O(log n)&#xff0c;其中n是BST中节点的数量。数据的排序&#xff1a;BST可以通过中序遍历得到有序的…

Idea启动Gradle报错: Please, re-import the Gradle project and try again

Idea启动Gradle报错&#xff1a;Warning:Unable to make the module: reading, related gradle configuration was not found. Please, re-import the Gradle project and try again. 解决办法&#xff1a; 开启步骤&#xff1a;View -> Tool Windows -> Gradle 点击refe…

HN 千赞热贴|创业 4 年,那些狠狠打我脸的技术选型

Hacker News 帖子 过年这段时间&#xff0c;Hacker News 上也涌现了不少好帖子&#xff0c;除了霸榜的 Sora 外&#xff0c;技术贴最靠前的就是这篇 (Almost) Every infrastructure decision I endorse or regret after 4 years running infrastructure at a startup。作者根据…

C#面:列出 .NET 中的几种循环方法,并指出它们的不同

fo r循环&#xff1a; for 循环是一种最常见的循环方法&#xff0c;它通过指定循环的起始值、终止条件和每次迭代的步长来控制循环。 for 循环适用于已知循环次数的情况。 while循环&#xff1a; while循环是一种在循环开始之前先判断条件是否满足的循环方法。只有当条件为…

【Django开发】0到1开发美多shop项目:图形和短信验证码。全md文档笔记(附代码,已分享)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论django商城项目相关知识。项目利用Django框架开发一套前后端不分离的商城项目&#xff08;4.0版本&#xff09;含代码和文档。功能包括前后端不分离&#xff0c;方便SEO。采用Django Jinja2模板引擎 Vue.js实现前后端…

【Java多线程】线程安全问题与解决方案

目录 1、线程安全问题 1.2、线程安全原因 2、线程加锁 2.1、synchronized 关键字 2.2、完善代码 2.3、对同一个线程的加锁操作 3、内容补充 3.1、内存可见性问题 3.2、指令重排序问题 3.3、解决方法 3.4、总结 volatile 关键字 1、线程安全问题 某个代码&#xff…