node.js命令行教程

node 命令行教程

本文先介紹原生的node.js實現命令行交互,瞭解原生的api,而後經過commander.js和inquirer.js實現一個完整的交互命令行工具。
項目地址vue

process (進程)

process對象是一個全局變量,它提供了當前node.js進程的信息並對其控制。由於其是一個全局變量因此無需在文件中引入。node

須要用到的幾個apiwebpack

  • process.argv
  • process.cwd()
  • process.stdin
  • process.stdout
  • process.stdin.resume()

process.argv

process.argv屬性返回一個數組。數組的第一個值是process.execPath,第二個是正在執行的JavaScript的文件路徑,其他參數爲其它命令參數,這是咱們來自定義命令的關鍵。git

示例

新建argv.jsgithub

//  argv.js
console.log(process.argv)

執行node命令 node argv.jsweb

node argv.js --name zhu
## 輸出
[ '/usr/local/bin/node', ## 執行當前腳本的Node二進制文件的絕對路徑
  '/Users/zhuhuilong/Node/Book/argv.js', ## 文件的絕對路徑
  '--name', ## 其他參數
  'zhu' ]

接收自定義的命令參數進行處理輸出shell

//  argv.js
console.log(process.argv)

let argvs = process.argv

let param = argvs.splice(2)
if(param[0] && param[0] == '--name'){
  if(param[1]){
    console.log(`hello ${param[1]}`)
  }else{
    console.log('請輸入name')
  }
}

運行argv.jsnpm

node argv.js --name zhu
## 輸出
[ '/usr/local/bin/node',
  '/Users/zhuhuilong/Node/Book/argv.js',
  '--name',
  'zhu' ]
hello zhu
param [ '--name', 'zhu' ]

process.stdin與process.stdout

process.stdin(標準輸入)json

process.stdin 屬性返回鏈接到 stdin (fd 0) 的流。 它是一個 net.Socket 流(也就是雙工流),除非 fd 0 指向一個文件,在這種狀況下它是一個可讀流。api

process.stdout(標準輸出)

process.stdout 屬性返回鏈接到 stdout (fd 1) 的流。 它是一個 net.Socket 流(也就是雙工流),除非 fd 1 指向一個文件,在這種狀況下它是一個可寫流。

process.stdin.resume()

  • 一個指向 標準輸入流(stdin) 的可讀流(Readable Stream)。標準輸入流默認是暫停 (pause) 的,因此必需要調用 process.stdin.resume() 來恢復 (resume) 接收。
  • 做爲流,process.stdin能夠在舊模式下使用。爲了兼容node v0.10之前的版本。在舊模式喜好使用stdin必須調用process.stdin.resume()。注意若是調用了process.stdin.resume() stdin將轉爲舊模式。

通俗來說就是控制檯等待咱們輸入內容不退出進程,對輸入輸出進行交互。

新建inputout.js

// inputout.js
process.stdin.setEncoding('utf8')

let argvs = process.argv

let param = argvs.splice(2)
if (param[0] && param[0] == '--name') {
  if (param[1]) {
    console.log(`hello ${param[1]}`)
  } else {
    process.stdout.write(`請輸入name:`)
    process.stdin.resume()
    process.stdin.on('data', chunk => {
      if (!!chunk.replace(/[\r\n]/g, '')) {
        process.stdout.write(`你輸入的name是: ${chunk}`)
        process.stdin.emit('end')
      } else {
        process.stdout.write(`請輸入name:`)
      }
    })
  }
}

process.stdin.on('end', () => {
  process.stdout.write('結束\n')
})

>執行node inputout.js --name
圖片描述
圖片描述

備註

在新版本node模式下可使用process.stdin.on("readable",()=>{})代替process.stdin.resume()恢復輸入流接收。

示例:

process.stdin.on("readable", () => {
  var chunk = process.stdin.read();
  console.log(typeof(chunk))
  if (chunk !==null) {
    process.stdout.write(`data: ${chunk}`);
    process.stdin.emit("end");
  }
});

process.stdin.on("end", () => {
  process.stdout.write("end");
});

從上面的示例咱們能夠拿到process.argv參數對其進行處理交互,但若是要實現更復雜的命令交互,使用上面的方法會很吃力。下面咱們使用commander.js和inquirer來實現一個完整的node命令行工具(建立項目模版)。

commander.js

node.js命令行界面的完整解決方案,受Ruby Commander啓發。

commander.js的API簡述

program.version() 聲明版本

const program = require('commander')
const pkg = require('../package.json')
program.version(pkg.version)

Options 解析

使用.option()方法定義commander的選項options,也能夠做爲選項的文檔。

var program = require('commander');
 
program
  .version('0.1.0')
  .option('-p, --peppers', 'Add peppers')
  .option('-P, --pineapple', 'Add pineapple')
  .option('-b, --bbq-sauce', 'Add bbq sauce')
  .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
  .parse(process.argv);
 
console.log('you ordered a pizza with:');
if (program.peppers) console.log('  - peppers');
if (program.pineapple) console.log('  - pineapple');
if (program.bbqSauce) console.log('  - bbq');
console.log('  - %s cheese', program.cheese);

添加自定義命令program.command()

var program = require('commander');
 
program
  .command('rm <dir>') //<>必選參數,若是是[]則是可選參數
  .option('-r, --recursive', 'Remove recursively')
  .action(function (dir, cmd) {
    console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
  })
 
program.parse(process.argv)

// command()可變參數
/** 命令command有且只有最後一個參數可變不固定的。 要使參數變量可變,必須將...附加到參數名稱。**/
program
  .version('0.1.0')
  .command('rmdir <dir> [otherDirs...]')
  .action(function (dir, otherDirs) {
    console.log('rmdir %s', dir);
    if (otherDirs) {
      otherDirs.forEach(function (oDir) {
        console.log('rmdir %s', oDir);
      });
    }
  });
 
program.parse(process.argv);

program.action() 定義命令的回調函數

var program = require("commander");

program
  .command("rm <dir>")
  .option("-r, --recursive", "Remove recursively")
  .option("-f, --force", "remove force")
  .action(function(dir, cmd) {
    // cmd爲option參數選項
    //console.log('cmd',cmd)
    if (cmd.recursive) {
      console.log("remove " + dir + " recursively");
    }
    if (cmd.force) {
      console.log("remove " + dir + " forcefully");
    }
  });

program.parse(process.argv);

inquirer.js

Inquirer.js使用NodeJs作的一個通用交互式命令行用戶界面的集合。具備經常使用的控制檯交互操做。

因爲交互的問題種類不一樣,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默認後綴。

建立cli.js

const program = require('commander')
const inquirer = require('inquirer')
const fs = require('fs')
const path = require('path')
const pkg = require('../package.json')

const CWD = process.cwd()

const promptList = [
  {
    type: 'list',
    message: '請選擇一種模版',
    name: 'template',
    choices: ['vue', 'angular', 'webpack-m-pages'],
    filter: function(val) {
      return val.toLowerCase()
    }
  }
]

program
  .version(pkg.version)
  .command('create <dir>')
  .description('create project template')
  .action(function(dir, cmd) {
    const TEMPLATE_PATH = path.join(CWD, dir)
    if (fs.existsSync(TEMPLATE_PATH)) {
    } else {
      fs.mkdirSync(TEMPLATE_PATH)
    }
    if (dir) {
      inquirer.prompt(promptList).then(anwsers => {
        console.log(anwsers)
      })
    }
  })

program.parse(process.argv)

運行 node cli/cli.js create vue
圖片描述

已經能夠運行了,咱們自定義一個命名替代每次都執行node

命令爲:test-cli create <dir>

一、建立bin文件夾,在bin文件夾下建立index.js文件

#!/usr/bin/env node

require('../cli/cli')

二、修改package.json文件
添加bin選項

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

三、執行npm link (若是沒有權限,執行sudo npm link)

四、測試
圖片描述

五、發佈 npm publish (若是未登陸需先 npm login登陸)

六、發佈完畢,需npm unlink解除本地的命令映射npm install -g XXX

相關文章
相關標籤/搜索