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

相關文章
相關標籤/搜索