文学起点网
当前位置: 首页 文学百科

cli怎么打开(打造属于自己的一款命令行)

时间:2023-07-17 作者: 小编 阅读量: 2 栏目名: 文学百科

前言如果你想了解命令行脚手架,这篇将带你入个门了解commander和inquirer库的使用。然后通过一个Demo示例来示范如何创作一个脚手架。commander首先需要知道commander这个npm库,它帮我们封装了解析命令行的能力。我们之后要做的脚手架都是基于commander的。但离人性化的命令行工具还有点距离,下面提供几种技巧:控制台输出语句的颜色有个仓库叫chalk,让我们可以自定义console.log输出的颜色。这对于命令行有非常好的可视化效果。

前言

如果你想了解命令行脚手架,这篇将带你入个门了解 commanderinquirer 库的使用。然后通过一个 Demo 示例来示范如何创作一个脚手架。

commander

首先需要知道 commander 这个 npm 库,它帮我们封装了 解析命令行 的能力。我们之后要做的脚手架都是基于 commander 的。

先了解几个简单的使用方式显示帮助&版本信息

const program = require('commander');// 定义程序名称,版本program.name(cliName).version(pkg.version);// 解析命令行program.parse(process.argv);

执行 node ./bin/fl-cli –help ,将看到如下效果:

D:\project\frontend-learn-cli>node ./bin/fl-cli --helpUsage: fl [options]Options:-V, --versionoutput the version number-h, --helpdisplay help for command

这个 program.parse 方法必须调用,不然命令行工具就不能“正常的工作了”。

输出信息中,能看到 Usage 条目,默认它向我们展示如何去使用这个命令,当然我们也可以更改它:

program.usage('<command> [options]');

Usage: fl <command> [options]

如何约定命令 Command?

命名一个 create 命令,约定用于创建应用(类似 vue create)

program.command('create').description('创建应用').action(() => {console.log('hello command');});

通过 help 命令,能看到 Commands 条目中增加的新命令信息:

D:\project\frontend-learn-cli>node ./bin/fl-cli --helpUsage: fl <command> [options]Options:-V, --versionoutput the version number-h, --helpdisplay help for commandCommands:create创建应用help [command]display help for command

执行 create 命令:

D:\project\frontend-learn-cli>node ./bin/fl-cli createhello command

如何定义命令参数 Options?

我们需要额外增加参数,来让命令应对多种情况,比如可以设置 -f 使得创建的应用强制覆盖当前路径:

program.command('create').description('创建应用').option('-f,', '是否强制创建').action((options, command) => {console.log(options);});

D:\project\frontend-learn-cli>node ./bin/fl-cli create -f{ f: true }

我们也能自定义参数值:

.option('-f,--force <path>', '是否强制创建')

D:\project\frontend-learn-cli>node ./bin/fl-cli create --force /use/local{ force: '/use/local' }

需要注意,如果用户输入了 非预期 的参数将报错:

D:\project\frontend-learn-cli>node ./bin/fl-cli create -abcerror: unknown option '-abc'

我们可以添加 allowUnknownOption() 方法,防止 非预期 参数影响命令的执行:

program.command('create').description('创建应用').option('-f,--force <path>', '是否强制创建').allowUnknownOption().action((options, command) => {console.log(options);});

D:\project\frontend-learn-cli>node ./bin/fl-cli create -abc{}

进阶技巧

如上,我们就能进行开发简单的命令行工具了。但离 人性化 的命令行工具还有点距离,下面提供几种技巧:

控制台输出语句的颜色

有个仓库叫 chalk ,让我们可以自定义 console.log 输出的颜色。这对于命令行有非常好的可视化效果。

我们对 –help 命令做个封装,在 help 信息末尾添加蓝色的帮助命令语句:

const chalk = require('chalk');exports.outputHelp = (cliName) => {console.log();console.log(`Run ${chalk.cyan(`${cliName} <command> --help`)} for detailed usage of given command.`);console.log();};

program.on('--help', () => {outputHelp(cliName);});

同时,遍历每个 Command 命令,也为其添加这一功能:

program.commands.forEach((c) => c.on('--help', () => outputHelp(cliName)));

效果展示

“命令/参数”错误的封装

由于命令错误,参数错误或者值漏填会导致命令行的出错,对于这类非预期的错误需要及时提示使用者,而不是只展示:error: option ‘-f,–force ‘ argument missing 这样的信息。

参考 Vue 的错误处理 我们可以覆写 commander 的方法,结合 chalk 加强输出错误信息:

var enhanceErrorMessages = (methodName, log) => {program.Command.prototype[methodName] = function (...args) {if (methodName === 'unknownOption' && this._allowUnknownOption) {return;}this.outputHelp();console.log(``chalk.red(log(...args)));console.log();process.exit(1);};};// 类似有:missingArgument,unknownOption,optionMissingArgument 方法enhanceErrorMessages('missingArgument', (argName) => {return `Missing required argument ${chalk.yellow(`<${argName}>`)}.`;});

加强错误显示

交互式命令行 inquirer

通过 commandoption 可以定义所有命令行需要的功能,但在与使用者交互会相当不友好(会面对大量的命令说明)。

相信用过 vue-cli 都知道:在创建项目时,我们可以跟随命令行的提示来选择对应需要的功能。

这种交互式的命令行可以通过 inquirer 来完成。

下面是采用了这种方式的效果图:

效果图

先定义一批 questions 交互问题:

const defaultQuestions = [// 列表选择{type: 'list',name: 'template',message: '请选择模板',choices: [{ name: 'express' }, { name: 'vue2' }],},// 输入{type: 'input',name: 'appName',message: '请输入应用名称',default() {return 'app';},},];const expressQuestions = [{type: 'checkbox',name: 'express.middleware',message: '请选择中间件',choices: [{ name: 'express.json', checked: true },{ name: 'express.urlencoded', checked: false },],when(answers) {return answers.template == 'express';},},];const questions = [...defaultQuestions, ...expressQuestions];

然后在命令的 action 回调中调用 inquirer.prompt 方法:

program.command('create').description('创建应用').option('-f,--force <path>', '是否强制创建')// .allowUnknownOption().action((options, command) => {inquirer.prompt(questions).then(async (answers) => {console.log(answers);});});

当交互结束后,这个 answers 将是我们自定义的结果值:

{template: 'express',appName: 'app',express: { middlewares: [ 'json' ] }}{template: 'express',appName: 'app',express: { middlewares: [ 'json' ] }}

Demo

再了解上面有关命令行的工具操作后,下面可以实际“造”一个脚手架工具了。

下面将提供一个创建 express 代码模板的脚手架。用于快速生成相关代码目录,而不用去技术栈网站去拷贝大量代码。(具体代码逻辑,在 npm 搜索 frontend-learn-cli 即可)

简单实现思路:

通过commander,实现对创建create指令的命令行解析

program.command('create').description('创建应用').action((options, command) => {//inquirer...});

添加inquirer定义好相关可选问题

inquirer.prompt(questions).then(async (answers) => {// 模板逻辑...// 模板类型(express, vue...)// 项目名称// 中间件选择// ...});

定义模板固定代码

根据自己对 express 的习惯,定义相关代码结构:

template|- express|- bin| www.ejs|- routes| health.js.ejs| app.js.ejs| package.json.ejs

注意:上面的文件都已 ejs 作为后缀。具体原因是:模板变量会根据 answers 变量,动态注入自定义值。

ejs 文件模板会张这个样子:

# app.js.ejs<% if (express.middlewares.includes('json')) { -%>app.use(express.json())<% } -%><% if (express.middlewares.includes('urlencoded')) { -%>app.use(express.urlencoded())<% } -%>

为什么选择 ejs

是抄 express-generate 这个库的,当然也可以根据自己喜好选择模板引擎。这种模板方式让我做这种脚手架变得很方便,只要把历史项目 demo 复制进来,改一通后缀即可。

通过 fs 读模板到指定路径

将模板内的文件通过 fs-extra 写到指令执行的当前路径下(文件具体操作这里就不详述了)

inquirer.prompt(questions).then(async (answers) => {try {// 创建目录_mkdirProjectDir(answers.appName, options.f);_writeFiles([{ dirtory: 'bin', fileName: 'www', answers },{ dirtory: 'routes', fileName: 'health.js', answers },{ dirtory: 'util', fileName: 'index.js', answers },{ fileName: 'app.js', answers },{ fileName: 'package.json', answers },]);} catch (err) {console.log(chalk.red(err.message));}});

发布脚手架

package.json 文件中,约定 bin 属性,并指向我们实现的 commander 的文件:

"bin": {"fel": "bin/fel-cli.js"},

然后通过 npm publish 发布我们的脚手架包,最后使用者通过 npm i xxx -g 下载就能用了。

    推荐阅读
  • 荷塘月色简笔画彩图(荷塘的场景图简笔画)

    今日份简笔画荷塘月色.感恩日记1.,我来为整理几张简单漂亮的荷塘月色简笔画彩图?以下简笔画图片总有一款是你喜欢的,希望对你有帮助来看看吧!荷塘月色简笔画彩图今日份简笔画荷塘月色.感恩日记1.荷塘月色好看的儿童画图片儿童简笔画大全荷塘月色简笔画儿童画

  • 直硬头发软化前后效果图(头发软化前后效果图)

    可以使头发变软,变柔顺,变贴服,且价格也很便宜,普通的美发沙龙价格为50到80元左右,软化比较自然。头发软化后几天可以洗刚做完软化2至3天不要洗头,刚做完软化不要用力拉头发,会有损发质和效果。软化也是伤头发的,不过比不停地做一次性夹头发而言小很多,如果是短发做软化还是不错的。如果想让头发蓬蓬的,最好不要全头做软化,甚至不建议做软化。具体情况,建议咨询理发师。用药水要用好一点的,对头发伤害才不会很大。

  • 赞美运动员的话(赞美运动员的话有什么)

    年轻的我们自信飞扬,青春的气息如同出生的朝阳,蓬勃的力量如同阳光的挥洒此时此刻,跑道便是我们精彩的舞台,声声加油便是我们最高的奖项论何成功,谈何荣辱,心中的信念只有一个:拼搏,我来为大家科普一下关于赞美运动员的话?赞美运动员的话年轻的我们自信飞扬,青春的气息如同出生的朝阳,蓬勃的力量如同阳光的挥洒。所有的努力都是为了迎接这一刹那,所有的拼搏都是为了这一声令下。

  • 长安uni-k车主反映这款车怎么样(新车长安UNI-K登场)

    据长安汽车最新消息,中大型SUVUNI-K官图曝光,这是长安UNI系列的第二款车型。新车将搭载蓝鲸系列2.0T发动机并匹配8AT变速箱,将于广州车展首发亮相。新车亮点1.采用了全新的“V”型面设计和无边界格栅。新车概况新车前脸依然采用无边界设计并融入了V型面概念,不同于UNI-T,UNI-K的大灯位置设计在了最上方。车尾方面采用了时下流行的贯穿式尾灯设计,与UNI-T的V型后导流造型不同,UNI-K采用了新的航天器式造型,立式尾灯十分显眼。

  • 渡劫经典语录(关于渡劫的语录精选)

    情到深处人孤独,爱至穷时尽沧桑堕落的天使啊,你无知的游走着。我将于茫茫人海中访我唯一灵魂之伴侣;得之,我幸;不得,我命。玲珑骰子安红豆,入骨相思君知否。于千万人之中遇见你所遇见的人,于千万年时间无涯的荒野里,没有早一步,也没有晚一步,刚巧赶上了。生命是一朵千瓣莲花,我拒绝了绽放的同时,我也拒绝了枯萎和零落。就算哭泣也要皱眉优雅,就算失败也要转身潇洒。之后我也学会了阳奉阴违,发生了什么与我再无所谓。

  • 孤城闭什么时候上映(谁是主演)

    以下内容大家不妨参考一二希望能帮到您!孤城闭什么时候上映《孤城闭》将于2020年起在湖南卫视上映播出。该剧主要由王凯、江疏影、任敏、杨玏、边程、叶祖新、喻恩泰、王楚然、刘钧、孙坚等主演。《孤城闭》改编自米兰lady同名小说,以北宋为背景,在风起云涌的朝堂之事与剪不断理还乱的儿女情长之间,还原了一个复杂而真实的宋仁宗。

  • 大众朗逸所有灯图解(认识汽车灯图解)

    大众朗逸所有灯图解作为新手,汽车灯光就是一道难题,下面我们一起通过图解来认识一下汽车各种灯光吧。双闪灯的作用是当车辆发生意外情况后,引起其他车辆警惕,防止发生追尾事故。当踩下制动踏板后,制动灯立即亮起,并发出红色灯光,提醒后方车辆。倒车灯是白色,作用是为了照亮车尾的路面,减少倒车时盲区,另外也是对后方的提醒。

  • 雪里红的腌制方法(做雪里红腌菜的步骤)

    下面更多详细答案一起来看看吧!雪里红的腌制方法雪里红摘干净,根部用刀劈开,正一层反一层放入盆中,取盐均匀地洒在雪里红上,腌制1-2天。烧开水放凉,加盐,搅拌均匀,盐水倒入雪里红中泡制一天。泡好的雪里红捆成一小捆放入密封罐,倒入泡雪里红的盐水,盖好密封罐,即吃即取。

  • 郑州婚纱照推荐哪家好(郑州拍婚纱照团购)

    中国红喜嫁秀爆朋友圈的婚纱照中式婚纱照新中式婚纱照婚纱照风格高级感婚纱照婚纱照秀禾服的中式嫁衣,是完美诠释了东方女性温婉古典美。让人完全移不开目光~每一个女孩子都应该拥有这样华丽的喜嫁风太精致完全属于中式婚纱照的浪漫感~

  • 胎梦最准的位置(从胎梦看看你腹中的孩子给你暗示了吗)

    估计生完孩子和正在孕期的妈妈都会经历过这种事情,就是我们会经常做梦,而且会梦见一些动物植物什么的,这在老人眼里属于“胎梦”。你梦见的什么会预示着即将出生的宝宝是男孩还是女孩。你的胎梦准不准,来看看一下别人的胎梦。哈哈,看来有些胎梦还是挺准的,或许都是巧合吧,总之,宝宝来了就是我们的命中注定。