当前位置: 首页 > 后端技术 > Node.js

闻起来真香!原来CLI开发也可以这么简单

时间:2023-04-03 23:03:38 Node.js

CLI(命令行工具,CommandLineInterface)大家都很熟悉了,比如create-react-app等等。今天介绍一个CLI工具开发框架,可以帮助我们快速搭建CLI工具。oclif(发音为“oh-cliff”)是一个命令行工具开发框架,功能丰富且易于开发。同时oclif还支持通过TypeScript进行开发,对于习惯使用TypeScript的同学来说非常友好。基本使用oclif提供了两种运行模式,一种是单命令模式,类似于curl,通过各种参数使用不同的功能。另一种是多命令模式,类似于git,可以定义子命令来实现不同的功能。下面两个例子分别展示了单命令模式和多命令模式的用法。$npxoclif单mynewcli?npm包名称(mynewcli):mynewcli$cdmynewcli$./bin/runhelloworld来自./src/index.js!在单命令模式下,src目录下会生成一个index.{ts,js}文件,我们在这个文件中定义命令。$npxoclifmultimynewcli?npm包名(mynewcli):mynewcli$cdmynewcli$./bin/run--versionmynewcli/0.0.0darwin-x64node-v9.5.0$./bin/run--helpUSAGE$mynewcli[COMMAND]COMMANDShello帮助显示帮助mynewcli$./bin/runhellohelloworldfrom./src/hello.js!在多命令模式下,src目录下会生成一个commands目录,该目录下的每个文件都是一个子命令。例如./src/commands/hello.ts,./src/commands/goodbye.ts。注意,在多命令模式下,命令和文件之间存在隐含的对应关系,例如src/commands目录下的文件是子命令。如果src/commands下有目录,目录下的多个文件会组成一个Topic。增加如下目录结构:package.jsonsrc/└──commands/└──config/├──index.ts├──set.ts└──get.ts然后,命令的最终执行形式为:mynewcli配置、mynewcli配置:设置和mynewcli配置:获取。定义命令无论是单命令模式还是多命令模式,开发者只需要定义一个类来继承Command类即可。importCommandfrom'@oclif/command'exportclassMyCommandextendsCommand{staticdescription='descriptionofthisexamplecommand'asyncrun(){console.log('runningmycommand')}}如上,当命令运行时,run方法会自动执行。Command还提供了很多工具和方法,比如this.log、this.warn、this.error、this.exit等,方便在运行时打印日志信息。命令行工具通常需要定义一些参数。oclif支持两种参数定义形式,一种是argument,用于定义有顺序要求的参数,另一种是flag,用于定义无顺序要求的参数。定义argumentargument的使用方法如下:$myclifirstArgsecondArg#参数顺序不能乱。我们可以这样定义参数:/获取对象形式的参数const{args}=this.parse(MyCLI)console.log(`runningmycommandwithargs:${args.firstArg},${args.secondArg}`)//你也可以以数组形式获取参数const{argv}=this.parse(MyCLI)console.log(`runningmycommandwithargs:${argv[0]},${argv[1]}`)}}我们可以定义argument参数的属性:staticargs=[{name:'file',//参数名,然后获取argv[name]形式的参数required:false,//是否必填?description:'outputfile',//参数说明hidden:true,//是否隐藏命令的帮助信息parse:input=>'output',//参数处理函数,可以改变输入的值userdefault:'world',//参数默认值options:['a','b'],//参数可选范围}]定义flagflag的用法如下:$mycli--force--file=./myfile我们可以这样定义标志参数:importCommand,{flags}from'@oclif/command'exportclassMyCLIextendsCommand{staticflags={//可以通过--force或-fforce指定参数:flags.boolean({char:'f'}),文件:flags.string(),}asyncrun(){const{flags}=this.parse(MyCLI)if(flags.force)console.log('--forceisset')if(flags.file)console.log(`--fileis:${flags.file}`)}}我们可以定义flag参数的属性:staticflags={name:flags.string({char:'n',//shortparameterNamedescription:'nametoprint',//参数说明hidden:false,//是否隐藏帮助信息multiple:false,//是否支持为该参数设置多个值env:'MY_NAME',//defaultvalue使用的环境变量名称options:['a','b'],//可选值列表parse:input=>'output',//处理用户输入default:'world',//默认值,也可以是返回字符串的函数required:false,//是否需要dependsOn:['extra-flag'],//其他依赖的标志参数列表exclusive:['extra-flag'],//不能与其他标志参数列表一起使用}),//布尔参数force:flags.boolean({char:'f',default:true,//defaultvalue,canbeafunctionthatreturnsabooleanvalue}),}usinglifecyclehooksoclif提供了一些生命周期钩子,允许开发人员执行一些额外的工具运行各个阶段的操作,我们可以这样定义一个钩子函数:import{Hook}from'@oclif/config'exportdefaultconsthook:Hook<'init'>=asyncfunction(options){`exampleinithookrunningbefore${options.id}`)}同时,你还需要在package.json中注册这个钩子函数:"oclif":{"commands":"./lib/commands","hooks":{"init":"./lib/hooks/init/example"}}oclif还支持定义多个钩子函数,它们将并行运行:"oclif":{"commands":"./lib/commands","hooks":{"init":["./lib/hooks/init/example","./lib/hooks/init/another_hook"]}}目前支持的生命周期钩子如下:init-inCLI完成初始化后,才找到对应的命令。预运行-在init完成并找到相应的命令之后,但在命令运行之前。postrun-命令完成运行后没有错误。command_not_found-在显示错误消息之前未找到相应的命令。使用插件oclif官方和社区提供了很多有用的插件,新开发的命令行工具可以使用,只需要在package.json中声明即可。{"name":"mycli","version":"0.0.0",//..."oclif":{"plugins":["@oclif/plugin-help","@oclif/plugin-not-found"]}}可用的插件是:@oclif/plugin-not-found在找不到命令时提供友好的“您是不是要找”消息。@oclif/plugin-plugins允许用户将插件添加到您的命令行工具。@oclif/plugin-update自动更新插件。@oclif/plugin-help帮助插件。@oclif/plugin-warn-if-update-available当更新可用时,显示提示更新的警告消息。@oclif/plugin-autocomplete为bash/zsh提供自动完成功能。错误处理运行命令行时难免会出现错误。oclif提供了两种错误处理方法。Command.catch每个Command实例都有一个catch方法,开发人员可以在其中处理错误。import{Command,flags}from'@oclif/command'exportdefaultclassHelloextendsCommand{asynccatch(error){//做某事或//重新抛出以在全局范围内处理throwerror;}}bin/run的catchbin/run是每个oclif命令行工具的入口文件,我们可以使用bin/run的catch方法来捕获错误,包括Command中重新抛出的错误。.catch(require('@oclif/errors/handle'))//或.catch((error)=>{constoclifHandler=require('@oclif/errors/handle');//对错误做任何额外的工作returnoclifHandler(error);})其他功能cli-uxoclif官方维护的cli-ux库提供了很多有用的功能。通过cliux.prompt()函数可以实现简单的交互功能。如果你有更复杂的交互需求,可以使用查询器。通过cliux.action可以实现旋转加载效果。通过cliux.table可以显示表格数据。node-notifier可以通过node-notifier实现跨平台的通知信息展示。常见的面试知识点、技术方案、教程,可以扫描二维码关注公众号“何里千寻”获取,也可以来这里https://everfind.github.io。

猜你喜欢