cli工具开发

1,461 阅读5分钟

cli工具开发

战士上战场,不会写cli,怎么搭脚手架

介绍

什么是cli?全称就是command-line interface,即命令行工具,输入一行命令,通过一些交互操作,帮你搭建项目脚手架

环境准备

node环境

开始

创建目录并初始化

mkdir test-cli && cd test-cli
touch index.js // 添加代码console.log('我要放大招啦')


在这时执行:node index.js 就可以运行这个文件了

其他运行方式

用命令行来运行

运行npm init,会生成一个package.json文件,添加配置:

"bin":{
    "test-cli":"./index.js"
},

然后在index.js中首行添加代码

#!/usr/bin/env node

这句话的意思其实就是用node来运行这个文件,当然同样可以把'node'换成'python'之类的
然后运行命令npm link 给当前项目创建一个软连接,这样就可以在任何目录下输入exercise-cli来执行这个项目里的index.js文件了,删除软连接npm unlink exercise-cli

用npm来运行

在package.json文件中加如下代码:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "exercise":"test-cli"
 }

这样就可以像我们平时运行项目一样通过npm run exercise 来运行了

直接运行

执行命令chown 755 index.js 将index.js设置为一个可执行文件,这样我们就可以直接在命令行中输入index.js 来运行这个文件了

拷贝项目模板

在项目根目录下创建如下文件, 就当是我们的项目模板了:

image.png

在index.js中加入代码:

const fse = require('fs-extra')
fse.copy(__dirname + '/templates', '.', (err) => {
  if(err) throw err
  console.log('项目模板拷贝成功')
})


新建一个项目目录,用来测试我们的exercise-cli

mkdir test-cli-project
cd test-cli-project

然后运行命令exercise-cli,执行结果:

image.png

这样就将项目模板拷贝到我们的项目里了

提示:因为原生的fs模块很简陋,比如:只能复制文件,不能复制文件夹,目录必须存在等等,所以这里用了第三方包 fs-extra

传参

在index.js中输入代码

console.log(process.argv)

运行 exercise-cli name age 输出:

image.png

由此可知:第一个参数为node路径,第二个参数是当前项目的路径,第三个往后就是自己传入的参数了

修改index.js代码

let params = process.argv.slice(2)

if (params.includes('user')) {
  console.log('收到参数"user",创建user文件')
  fse.createFileSync('./user.js')
}
if (params.includes('utils')) {
  console.log('收到参数"utils",创建utils文件')
  fse.createFileSync('./lib/utils.js')
}

根据输入的参数来判断并执行相关的逻辑,输出结果:

image.png

上色

安装插件chalk并引入

//命令行安装
npm install chalk
//index.js引入
var chalk = require('chalk');

修改index.js代码:

if (params.includes('user')) {
  console.log(`收到参数"${chalk.red('user')}",${chalk.blue.underline.bold('创建user文件')}`)
  fse.createFileSync('./user.js')
}
if (params.includes('utils')) {
  console.log(`收到参数"${chalk.red('utils')}",${chalk.blue.underline.bold('创建utils文件')}`)
  fse.createFileSync('./lib/utils.js')
}

输出结果:

image.png

对话

安装并引入

npm i inquirer -s
// 引入
const inquirer = require('inquirer')

基本参数

  • type:表示提问的类型,包括:input, confirm, list, rawlist, expand, checkbox, password, editor;
  • name: 存储当前问题回答的变量;
  • message:问题的描述;
  • default:默认值;
  • choices:列表选项,在某些type下可用,并且包含一个分隔符(separator);
  • validate:对用户的回答进行校验;
  • filter:对用户的回答进行过滤处理,返回处理后的值;
  • transformer:对用户回答的显示效果进行处理(如:修改回答的字体或背景颜色),但不会影响最终的答案的内容;
  • when:根据前面问题的回答,判断当前问题是否需要被回答;
  • pageSize:修改某些type类型下的渲染行数;
  • prefix:修改message默认前缀;
  • suffix:修改message默认后缀。

使用

基本示例
const questions = [
  {
    type: 'input',
    name: '姓名',
    message: '请输入你的真实姓名',
    default: '尼古拉斯'
  }
]

inquirer.prompt(questions).then(answer => {
  console.log(answer)
})
// async function test() {
//   let answer = await inquirer.prompt(questions)
//   console.log(answer)
// }
// test()

结果:

image.png

更多示例

const questions = [
  {
    type: 'input',
    name: 'name',
    message: '请输入你的真实姓名',
    default: '尼古拉斯'
  },
  {
    type: 'input',
    name: 'phone',
    message: '请输入11位手机号',
    validate:val=>{
			if(val.match(/\d{11}/g)){
				return true
			}
			return '请输入11位数字'
		}
  },
  {
    type: 'confirm',
    name: 'access',
    message: '下班了吗?'
  },
  {
    type: 'confirm',
    name: 'access',
    message: '确定要加班继续干吗?',
    when: answers=>{
			return answers.assess
		}
  },
  {
		type:'rawlist',
		message:'要加班几小时?',
		name:'eductionBg',
		choices:[
			"1小时",
			"2小时",
			"通宵"
		],
		filter:val=>{//将选择的内容后面加学历
			return '今晚要加班' + val
		}
  },
  {
		type:'expand',
			message:'夜宵吃啥?',
			name:'fruit',
			choices: [
			{
				key: "p",
				name: "泡面",
				value: "泡面"
      },
      new inquirer.Separator(),
			{
				key: "m",
				name: "面包",
				value: "面包"
      },
      new inquirer.Separator('------华丽的-------'),
      {
				key: "n",
				name: "不吃了",
				value: "不吃了"
      },
		]
  },
  {
		type:'password',
		message:'请输入你的银行卡密码:',
		name:'pwd'
	}
]

inquirer.prompt(questions).then(answer => {
  console.log(answer)
})


结果:

image.png

登堂入室

在我们学前端时是先学HTML,js,css等,基础学会了真正写项目时会用jQuery,vue,react等框架之类的
这里也一样,cli的基本操作了解了,真正实战时用一些工具会更加效率, 下面介绍commander的简单使用

安装并引入commander

npm i commander -s

const { program } = require('commander')

基本使用

在index.js中写入

program.version('0.0.1') // 设置版本
program
  .option('-e, --eat', '今晚吃饭吗') // 普通用法
  .option('-w, --what-food <type>', '吃什么') // 带参数,key是两个单词
  .option('-s, --small <size>', '大份还是小份', '小份') // 带参数,并且有默认值

program.parse(process.argv) // 解析参数

console.log('所有参数:', program.opts())
console.log('eat:', program.eat)
console.log('small:', program.small)
console.log('whatFood:', program.whatFood)


这里'.option'可以给program添加参数,经过解析后可以很方便的获取参数,看以下实验
命令行输入:exercise-cli -h 

image.png


exercise-cli -V
image.png


 exercise-cli
image.png


exercise-cli -ew 烧鸡 两个参数之间的-可以省略
image.png


exercise-cli -e -s 大份 -w 烧鸡 多个参数
image.png


自定义处理参数

在index.js中写入

function myParseInt(value) {
  return parseInt(value);
}

program
  .option('-i, --integer <num>', '会自动转换成int类型', myParseInt)

program.parse(process.argv) // 解析参数

if (program.integer) console.log('integer:', program.integer)


命令行输入:exercise-cli -i 1.2

image.png

自定义命令

program
  .command('custom <name> [fileName]')
  .description('自定义命令,可以接受参数')
  .action((source, destination) => {
    // 执行该命令的回调
    console.log('执行回调')
    console.log('参数:', source);
  })

  program.parse(process.argv)


命令行输入exercise-cli -h

image.png


可以看到多了一个命令,试一下:exercise-cli custom user.js
image.png

结束

到这里cli工具开发就介绍完了,快去实战吧



参考文章:用一次就会爱上的cli工具开发