cli--脚手架原理示例讲解

脚手架

主要使用的命令行工具

  • commander主要采用的是node.js的API中的events监听事件
  • inquirer主要采用的是node.js的API中的readline进行问询

实现原理

主要采用node.js的API,详细说明请看http://nodejs.cn/api/events.htmlhtml

  • events:事件触发器

建立events的实例commander,经过commander.on(name,fn)函数绑定事件,commander.emit(name)用于触发事件vue

  • process:进程获取执行参数,执行路径等

process.argv:返回一个数组,第一个元素process.execPath,第二个元素正在执行的 JavaScript 文件的路径,其余的命令行参数node

简单示例以下:git

const EventEmitter = require('events')
        
        //建立events的子类
        class Commander extends EventEmitter{
          constructor(name){
            super()
            this.name = name
          }
        
          action(fn){
            fn.apply(this,arguments)
          }
        }
        const commander = new Commander()
        //添加监听
        commander.on('command:create',()=>{
          console.log('执行 create 命令')
        })
        
        commander.on('option:help',()=>{
          console.log('执行 help 选项')
        })
        
        commander.action(()=>{
          return console.log('执行 action')
        })
        
        
        //触发监听
        if(process.argv.length>2){
          process.argv.forEach(v=>{
            //判断是command仍是option
            if(/^--/.test(v)){
              const optionStr = v.replace(/^--(.*)$/,'$1')
              commander.emit(`option:${optionStr}`)
            } else {
              commander.emit(`command:${v}`)
            }
            
          })
        }
        console.log('process.argv',process.argv)
复制代码

运行命令输出:github

  • readline:逐行读取

主要使用readline.Interface 类,经过createInterface()方法建立Interface实例,每一个实例都关联input输入流(必填项)和output输出流api

const readline = require('readline');
        const rl = readline.createInterface({
            input: process.stdin,
            output: process.stdout
        })
复制代码

使用rl.input.on('keypress')来监听输入内容是否结束数组

//监听回车
        rl.input.on('keypress', (value,key)=>{
         //回车
          if(key.name === 'enter' || key.name === 'return') {
            console.log('已监听到结束')
          }
        })
复制代码

使用rl.question()发出提问,并处理回答app

rl.question('你最喜欢什么?', (answer) => {
          console.log(`你最喜欢的是 ${answer}`);
      });
复制代码

完整的示例以下:函数

const readline = require('readline') //逐行读取
        const EventEmitter  = require('events') //监听事件
        const ansiEscapes = require('ansi-escapes') //移动光标的插件
        const chalk = require('chalk') // 设置输出内容的颜色
        const commander = new EventEmitter()
        
        //问题
        const questions = [
          {
            name:'name',
            type:'input',
            default:'logmei',
            message:'请输入名称'
          },
          {
            name:'version',
            type:'input',
            default:'1.0.0',
            message:'请输入版本号'
          },
          {
            name: 'template',
            type: 'input',
            default: 'simple_vue_module',
            message: '请输入模板'
          }
        ] 
        
        //回答
        const answers = {}
        
        //读取输入流
        const rl = readline.createInterface({
          terminal:true,
          input:process.stdin,
          output:process.stdout
        })
        
        //提问入口
        const inquirer = (function(){
          let count = 0 //私有变量,读取下一条
          return function(){
            if(count === questions.length ) {
              //输出结果
              rl.output.write(ansiEscapes.cursorLeft)
              console.log(chalk.blue('answers',JSON.stringify(answers)))
              //程序退出
              rl.close()
              process.exit()
            } else {
              rl.question(questions[count].message+':',(answer)=>{
                //没有输入内容,为默认内容
                answers[questions[count].name] = answer === '' ? questions[count].default : answer
                //默认内容回显
                 if(answer===''){
                  // 设置光标为上一行的结尾
                   rl.output.write(ansiEscapes.cursorUp(1)+ ansiEscapes.cursorForward(questions[count].message.length*2+1))
                   // 回写内容
                   rl.output.write(chalk.green(questions[count].default))
                 }
                 //修改光标位置
                 rl.output.write(ansiEscapes.cursorDown(1))
                // console.log('answers',answers)
                count++
              })
            }
           
          }
        })(questions)
        
        //监听回车
        rl.input.on('keypress', (value,key)=>{
          if(key.name === 'enter' || key.name === 'return') {
            inquirer()
          }
        })
        //绑定create事件
        commander.on('create',()=>{
          inquirer()
        })
        //触发create事件
        commander.emit('create')
复制代码

使用命令行工具开发的脚手架

辅助工具

模板

使用工具开发的脚手架代码https://github.com/logmei/cli_bytools

相关文章
相关标签/搜索