<font id="zqva1"></font>
<rt id="zqva1"></rt>
  • <tt id="zqva1"></tt>
    <cite id="zqva1"></cite>

    <cite id="zqva1"><noscript id="zqva1"></noscript></cite>
      <rp id="zqva1"><meter id="zqva1"></meter></rp>

        <cite id="zqva1"></cite>
          <b id="zqva1"></b>
          <rp id="zqva1"></rp>
          <cite id="zqva1"></cite>

          <rt id="zqva1"></rt>

        1. <rp id="zqva1"></rp>

          用node.js開發一個可交互的命令行應用

          時間:?2017-12-25閱讀:?1051標簽:?node

          近幾年, Node.js 在軟件開發的一致性上助力很大.無論是前端開發,服務端腳本,跨平臺桌面/移動端應用或是物聯網應用,Node.js 都可以幫你完成.由于 Node.js 的出現,編寫命令行工具比之前容易很多,這不是隨意說說,而是可交互,真正有價值的并且能減少開發耗時的命令行工具.

          譯者:Icarus
          原文鏈接: How To Develop An Interactive Command Line Application Using Node.js

          如果你是一名前端開發者,那你一定聽說過或者使用過諸如 Gulp, Angular CLI, Cordova, Yeoman或其它的命令行工具.舉個例子,在使用 Angular CLI 的情況下,通過執行ng new <project-name>這個命令,你會創建一個基于基礎配置的 Angular 項目.像 Yeoman 這樣的命令行工具會在運行過程中需要你輸入一些內容從而幫助你個性化定制項目的配置.Yeoman 中的生成器(generators)會幫助你在生產環境部署項目.這就是我們今天要學習的部分.

          拓展閱讀

          A Detailed Introduction To Webpack
          An Introduction To Node.js And MongoDB
          Server-Side Rendering With React, Node And Express
          Useful Node.js Tools, Tutorials And Resources

          在這個教程中,我們會開發一個命令行應用,它可以接收一個 CSV 格式的用戶信息文件,通過使用  SendGrid API可以像這些用戶發送電子郵件.下面是教程的內容大綱:

          1. “Hello,World”
          2. 處理命令行參數
          3. 運行時的用戶輸入
          4. 異步網絡會話
          5. 美化控制臺的輸出
          6. 封裝成 shell 命令
          7. JavaScript 之外

          “Hello,World”

          這個教程假設你的系統里已經安裝好了 Node.js. 如果你沒有,請先安裝它.在安裝 Node.js的同時會附帶一個叫 npm 的包管理器.使用 npm 你可以安裝很多開源的包.你可以在 npm 的官網站點上獲取全部的包列表.這個項目我們會用到一些開源的模塊(之后會更多).現在,讓我們用 npm 創建一個 Node.js 項目.

          npm init
          name: broadcast
          version: 0.0.1
          description: CLI utility to broadcast emails
          entry point: broadcast.js

          我創建了一個名為 broadcast 的文件夾,在里面我執行了 npm init 命令.正如你看到的那樣,我已經提供了諸如項目名稱,描述,版本號和入口文件等項目的基礎信息.入口文件是最主要的 JS 文件,在這里腳本開始編譯運行.Node.js 默認把 index.js 文件當做入口文件,而在這個例子里我們把入口文件改為 broadcast.js.當你執行 npm init命令的時候,你會得到更多的選項,比如 Git 倉庫地址,開源許可證和作者名.你可以填寫這些選項或者空著它們.

          npm init成功執行之后,你會在文件夾里看到一個 package.json文件已經創建好了.這是我們的配置文件.與此同時,它也保存著我們在創建項目時提供的信息.你可以在 npm 官方文檔中瀏覽更多有關package.json的內容.

          既然項目已經創建好了,那就讓我們創建一個”Hello world”程序.開始之前,你需要在你的項目中新建一個 broadcast.js文件,這個是之后主要用到的文件,在文件中寫入如下代碼段:

          console.log('hello world');

          現在讓我們運行一下.

          node broadcast
          hello world

          正如你看到的那樣,”hello world”在控制臺打印出來了.你可以使用node broadcast.js或者node broadcast來執行腳本. Node.js足以分辨它們的區別.

          根據package.json的文檔,有一個名為 dependencies 的選項,在這里我們可以填寫所有我們計劃在項目中使用的第三方模塊,同時附上它們的版本號.像之前提到的,我們會使用很多第三方的開源模塊去開發這個工具.在我們的項目中,package.json像下面這樣:

          {
            "name": "broadcast",
            "version": "0.0.1",
            "description": "CLI utility to broadcast emails",
            "main": "broadcast.js",
            "license": "MIT",
            "dependencies": {
              "async": "^2.1.4",
              "chalk": "^1.1.3",
              "commander": "^2.9.0",
              "csv": "^1.1.0",
              "inquirer": "^2.0.0",
              "sendgrid": "^4.7.1"
            }
          }


          你一定注意到了,我們會用到 Async, Chalk, Commander, CSV, Inquirer.js 和 SendGrid這些模塊.隨著我們教程的深入,這些模塊的具體用法和細節會慢慢解釋.

          處理命令行參數

          讀取命令行參數并不是很難.你可以用 process.argv 很簡單的去讀取它們.但是分析它們的取值和選項是一項很繁瑣的工作.為了避免重復造輪子,我們會使用 Commander 模塊.Commander 是一個開源的 Node.js模塊,它可以幫助你編寫交互式的命令行工具.它帶來很多解釋命令行選項的有趣特性并且擁有類似 Git 的子命令,但我最喜歡的是它可以自動生成幫助命令.你不需要去寫額外的代碼 - 執行 --help 或者 -h選項就可以了.當你開始定義各種各樣的命令行選項時,幫助命令會自動生成,讓我們來試一試:

          npm install commander --save

          這會在你的 Node.js 項目中安裝 Commander 模塊.在 npm install 命令中加入 --save參數會自動將 Commander 模塊添加到 package.json 文件中的 dependencies 參數中.在我們之前填寫的 package.json 文件中,我們已經把所有的依賴都寫好了,所以我們可以不加 --save 參數.

          var program = require('commander');
          program
            .version('0.0.1')
            .option('-l, --list [list]', 'list of customers in CSV file')
            .parse(process.argv)
          console.log(program.list);

          正如你看到的那樣,處理命令行的參數就是這么直截了當.我們已經定義了一個 --list 參數.現在,我們在 --list 參數后面提供任何值,這個值都會儲存在方括號包裹中的變量里.在這里,就是 list.你可以從 program 這個 Commander 的實例中獲取到 list 的值.現在,這個程序只接受一個文件路徑作為 --list 參數的取值,然后把它打印在控制臺中.

          node broadcast --list input/employees.csv
          input/employees.csv

          你一定注意到了這里我們定義了另一個方法 version.任何時候只要我們帶著 --version或者 -V參數執行命令,定義中的值就會傳入這個方法并且把它打印在控制臺.

          node broadcast --version
          0.0.1

          相似的,當你帶著 --help 參數執行命令的時候,控制臺會打印出所有你定義的選項和子命令.在這里,看起來是下面這樣的:

          node broadcast --help
          Usage: broadcast [options]
          Options:
              -h, --help                 output usage information
              -V, --version              output the version number
              -l, --list <list>          list of customers in CSV file


          既然已經可以在命令行參數中接受文件路徑,我們就可以開始使用 CSV 模塊來讀取 CSV 文件了.CSV 模塊是處理 CSV 文件的一個解決方案.從創建一個 CSV 文件到解析處理它,這個模塊可以解決任何相關的問題.

          因為計劃使用 sendGrid API 來發送電子郵件,我們可以使用下面的文檔作為一個 CSV 文件的示例.使用 CSV 模塊,我們會讀取其中的數據并且在表格中展示姓名和對應的電子郵件地址.

          First name Last name Email
          Dwight Schrute dwight.schrute@dundermifflin.com
          Jim Halpert jim.halpert@dundermifflin.com
          Pam Beesly pam.beesly@dundermifflin.com
          Ryan Howard ryan.howard@dundermifflin.com
          Stanley Hudson stanley.hudson@dundermifflin.com

          現在,讓我們寫一個程序來讀取 CSV 文件并且將其中的數據打印在控制臺.

          const program = require('commander');
          const csv = require('csv');
          const fs = require('fs');
          program
            .version('0.0.1')
            .option('-l, --list [list]', 'List of customers in CSV')
            .parse(process.argv)
          let parse = csv.parse;
          let stream = fs.createReadStream(program.list)
              .pipe(parse({ delimiter : ',' }));
          stream
            .on('data', function (data) {
              let firstname = data[0];
              let lastname = data[1];
              let email = data[2];
              console.log(firstname, lastname, email);
            });

          使用 Node.js原生的文件模塊,我們可以通過命令行參數來讀取文件.文件模塊執行后是我們提前定義的事件 data,它會在數據被讀取時被觸發.CSV 模塊中的 parse 方法會將 CSV 文件分割成獨立的行并且觸發多次 data 事件.每一個 data 事件傳遞一個列數據的數組.這些數據就會以下面這種形式被打印出來:

          node broadcast --list input/employees.csv
          Dwight Schrute dwight.schrute@dundermifflin.com
          Jim Halpert jim.halpert@dundermifflin.com
          Pam Beesly pam.beesly@dundermifflin.com
          Ryan Howard ryan.howard@dundermifflin.com
          Stanley Hudson stanley.hudson@dundermifflin.com


          運行時的用戶輸入

          現在我們了解了如何接收命令行參數并且去解析它們.但是如果我們希望在運行過程中接受用戶的輸入呢?一個名為 Inquirer.js 的模塊讓我們接受許多種輸入的方式,從直接輸入文本到輸入密碼甚至到一個多選列表.

          在這個樣例里,我們會在運行過程的輸入中接收發送者的電子郵件地址和姓名.

          let questions = [
            {
              type : "input",
              name : "sender.email",
              message : "Sender's email address - "
            },
            {
              type : "input",
              name : "sender.name",
              message : "Sender's name - "
            },
            {
              type : "input",
              name : "subject",
              message : "Subject - "
            }
          ];
          let contactList = [];
          let parse = csv.parse;
          let stream = fs.createReadStream(program.list)
              .pipe(parse({ delimiter : "," }));
          stream
            .on("error", function (err) {
              return console.error(err.message);
            })
            .on("data", function (data) {
              let name = data[0] + " " + data[1];
              let email = data[2];
              contactList.push({ name : name, email : email });
            })
            .on("end", function () {
              inquirer.prompt(questions).then(function (answers) {
                console.log(answers);
              });
            });

          首先,你會注意到上面的示例中我們創建了一個名為 contactList 的數組,它是我們用來存儲 CSV 文件中的數據的.

          Inquirer.js 帶來了一個名為 prompt 的方法,這個方法接收一個問題的數組,里面保存著運行期間我們想要問的問題.在這里,我們想要知道發送者的姓名,電子郵件地址和他們郵件的主題.我們已經創建了一個保存了所有問題的 questions 數組.這個數組接受對象作為數組成員,對象中包含 type 屬性,可以選擇 input,password和 raw list等值.完整的可用值可以在官方文檔中找到.在這里,name 定義了保存用戶輸入的索引(key).prompt 方法返回一個 promise 對象.當用戶回答所有的問題之后,這個 promise 對象會觸發一系列的成功或失敗的回調.answers 作為 then 回調的參數傳遞,用戶的回復可以通過它來獲取.下面是執行代碼時發生的事情:

          node broadcast -l input/employees.csv
          ? Sender's email address -  michael.scott@dundermifflin.com
          ? Sender's name -  Micheal Scott
          ? Subject - Greetings from Dunder Mifflin
          { sender:
             { email: 'michael.scott@dundermifflin.com',
               name: 'Michael Scott' },
            subject: 'Greetings from Dunder Mifflin' }


          異步網絡會話

          既然我們已經可以從 CSV 文件中讀取接收者的數據并且接收到發送者通過命令行提示填寫的信息,是時候發送電子郵件了.我們會使用 SendGrid API來發送電子郵件.

          let __sendEmail = function (to, from, subject, callback) {
            let template = "Wishing you a Merry Christmas and a " +
              "prosperous year ahead. P.S. Toby, I hate you.";
            let helper = require('sendgrid').mail;
            let fromEmail = new helper.Email(from.email, from.name);
            let toEmail = new helper.Email(to.email, to.name);
            let body = new helper.Content("text/plain", template);
            let mail = new helper.Mail(fromEmail, subject, toEmail, body);
            let sg = require('sendgrid')(process.env.SENDGRID_API_KEY);
            let request = sg.emptyRequest({
              method: 'POST',
              path: '/v3/mail/send',
              body: mail.toJSON(),
            });
            sg.API(request, function(error, response) {
              if (error) { return callback(error); }
              callback();
            });
          };
          stream
            .on("error", function (err) {
              return console.error(err.response);
            })
            .on("data", function (data) {
              let name = data[0] + " " + data[1];
              let email = data[2];
              contactList.push({ name : name, email : email });
            })
            .on("end", function () {
              inquirer.prompt(questions).then(function (ans) {
                async.each(contactList, function (recipient, fn) {
                  __sendEmail(recipient, ans.sender, ans.subject, fn);
                });
              });
            });


          使用 SendGrid 模塊需要我們去獲取一個 API key.你可以在 SendGrid 的儀表盤生成這個 API key(需要創建一個賬戶),我們需要把它存在 Node.js 環境變量的 SENDGRID_API_KEY中.你可以使用 process.env 來獲取環境變量.

          在上面的代碼中,我們使用 SendGrid API 和 Async 模塊異步發送郵件.Async 模塊是 Node.js 中最有用的模塊之一.處理異步回調經常會導致回調地獄, 這通常出現在你的一個回調函數里處理了太多其他的回調函數,導致回調沒有盡頭.對于一個 JavaScript 開發者來說處理回調中的錯誤太過復雜,而 Async 模塊可以幫你去解決回調地獄,提供了像 each, series, map 等許多實用的方法.這些方法能幫助我們更好的組織代碼,從另一個方面講,會讓我們的異步代碼更像同步的寫法.

          在這個示例中,相較于向 SendGrid 發送同步請求,我們選擇發送異步請求來發送電子郵件.基于請求的響應,我們會發送隨后的請求,使用 Async 模塊中的 each 方法,我們遍歷了 contactList 數組并且觸發 __sendEmail函數.這個函數接受收件人和發送人的信息,郵件主題和異步請求的回調函數.__sendEmail 使用SendGrid API來發送電子郵件,它的官方文檔上可以了解更多關于它的內容.一旦一封電子郵件成功送達,異步請求的回調函數就會觸發,接著就會根據 contactList 下一項的內容繼續發送郵件.到這里,我們已經成功創建了一個可以接收 CSV 文件輸入并且發送郵件的命令行應用!


          美化控制臺的輸出

          既然已經完成了基本功能,現在讓我們想一下如何美化控制臺的輸出結果,比如說錯誤和成功的信息.為了實現這個功能,我們需要使用用來優化控制臺命令展示的 Chalk 模塊.

          stream
            .on("error", function (err) {
              return console.error(err.response);
            })
            .on("data", function (data) {
              let name = data[0] + " " + data[1];
              let email = data[2];
              contactList.push({ name : name, email : email });
            })
            .on("end", function () {
              inquirer.prompt(questions).then(function (ans) {
                async.each(contactList, function (recipient, fn) {
                  __sendEmail(recipient, ans.sender, ans.subject, fn);
                }, function (err) {
                  if (err) {
                    return console.error(chalk.red(err.message));
                  }
                  console.log(chalk.green('Success'));
                });
              });
            });

          在上面的代碼片段中,我們在發送郵件的過程中添加了一個回調函數,它在任何一個異步過程里由于執行過程中的錯誤導致的完成或中斷都會被觸發.當異步過程沒有完成,控制臺會打印紅色的信息,相反的,我們用綠色打印成功的信息.

          如果你瀏覽一下 Chalk 的文檔,你會發現有很多可自定義的選項,包括一系列的控制臺顏色可選,還有下劃線和加粗字體.


          封裝成 shell 命令

          既然我們的工具已經完成了,是時候去讓它執行起來像一個普通的 shell 命令了.首先,讓我們在 broadcast.js 的頂部添加一個注釋(shebang),這會告訴 shell 如何去執行這個腳本.

          #!/usr/bin/env node
          const program = require("commander");
          const inquirer = require("inquirer");

          現在讓我們配置一下 package.json 來讓命令變得可執行.

          "description": "CLI utility to broadcast emails",
          "main": "broadcast.js",
           "bin" : {
              "broadcast" : "./broadcast.js"
          }


          我們已經添加了一個新的屬性 bin ,在這里我們提供了執行 broadcast.js 需要用到的命令.最后一步,讓我們把腳本裝載到全局環境上,這樣我們就可以像一個普通的 shell 命令一樣去執行它.

          npm install -g

          在執行這個命令之前,確認你在項目的目錄中.安裝完成后,你可以進行測試.

          broadcast --help

          這應該會打印出執行 node broadcat --help 后所有可用的選項.現在你可以準備向世界展示你自己的工具了.

          有一件事要記住: 在開發過程中,當你只是簡單的執行 broadcast 命令,任何你做的改變都不會生效,你會意識到命令的目錄和你正在工作的項目目錄是不同的.為了避免這種情況,在你的項目文件夾中運行 npm link???即可,這樣會在你執行的命令和目錄之間自動建立聯系.在這之后,無論你做了任何改動同樣也會反映在 broadcast 命令中.

          在 JavaScript 項目之外,有很多類似的 CLI 工具在很多領域都運轉良好.如果你在軟件開發領域有一些經驗,你就會明白 Bash 工具在開發過程中是必不可少的.從部署腳本到備份的定時任務,你可以用 Bash 腳本自動化任何工作.在 Docker, Chef 和 Puppet 成為事實上的基礎設施管理標準之前,全靠 Bash 來完成這些工作.雖然 Bash 腳本總是會存在問題.它不能簡單的融入到開發工作流中.通常情況,我們會使用各種各樣的編程語言,而Bash 極少作為核心開發的一部分.甚至在 Bash 腳本中寫一個簡單的條件判斷都要無窮無盡的調試和查閱文檔.

          但是,使用 JavaScript 能夠讓整個過程變得更簡單更搞笑.所有工具都是天然跨平臺的.如果你想在運行一個原生的 shell 命令,比如 git, mongodb或者 heroku, 使用 Node.js 的 Child Process 模塊非常容易實現.這讓我們可以在編寫工具的時候充分享受到 JavaScript 的便利.

          吐血推薦

          1.站長廣告聯盟: 整理了目前主流的廣告聯盟平臺,如果你有流量,可以作為參考選擇適合你的平臺點擊進入...

          2.休閑娛樂: 直播/交友    優惠券領取   網頁游戲   H5游戲

          鏈接: http://www.modern-decoration.com.cn/article/detial/276

          怎么卸載nodejs?

          Node.js是一個Javascript運行環境,可以使Javascript這類腳本語言編寫出來的代碼運行速度獲得極大提升,那么安裝后該如何卸載呢?下面本篇文章就來給大家介紹一下Windows平臺下卸載node.js的方法,希望對大家有所幫助。

          nodejs適合做什么?

          面對一個新技術,多問幾個為什么總是好的。既然 PHP、Python、Java 都可以用來進行后端開發,那么為什么還要去學習 Node.js?Node.js適合做什么?Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環境,一個讓 JavaScript 運行在服務端的開發平臺。

          理解 nodeJS 中的 buffer,stream

          在Node.js開發中,當遇到 buffer,stream,和二進制數據處理時,你是否像我一樣,總是感到困惑?這種感覺是否會讓你認為不了解它們,以為它們不適合你,認為而這些是Node.js作者們的事情?

          什么是node repl?

          Node REPL(Read Eval Print Loop)是Node自帶的交互式解釋器(又名Node shell),表示一個電腦的虛擬環境,類似 Window 系統的終端或 Unix/Linux shell,我們可以在終端中輸入命令,并接收系統的響應。

          node怎么更新升級?

          如果你的node安裝的比較早,現在最新的版本比自己安裝的高,則可以通過升級的方式更新到指定的版本和最新的版本。下面本篇文章就來給大家介紹windows下和linux更新升級node版本的方法。

          node modules是什么?

          在node.js中modules(模塊)與文件是一一對應的,也就是說一個node.js文件就是一個模塊,文件內容可能是我們封裝好的一些JavaScript方法、JSON數據、編譯過的C/C++拓展等,在關于node.js的誤會提到過node.js的架構

          在Node.js 12 中使用 ESM

          Node.js 12 之后開始支持 ECMAScript Modules(簡稱ESM),不過并不是默認開啟或者自動切換。坦率地說我也卡了一陣子才搞清楚怎么直接使用。簡單記一下吧。

          路徑 alias 在 Node 中的最佳姿勢

          根據當前自己已有的知識體系,先想想有哪幾種解決方案,然后再去查找業界的解決方案,這樣,我們才能不斷完善自己的知識體系,培養足夠的思維能力。

          nodejs做后端的好處有哪些

          Node.js是服務器端的 JavaScript 運行環境,它具有無阻塞(non-blocking)和事件驅動(event-driven)等的特色。Node.js 使用了一個事件驅動、非阻塞式 I/O 的模型,使其輕量又高效。

          Node.js v13.2.0 開始支持ES modules了

          Node.js 前不久發布了v13.2.0,宣布開始支持ES modules。在此之前,想要在node中使用ES modules,需要添加--experimental-module。v13.2.0版本后,可以直接使用ES modules了。

          fly63.com版權所有,內容以共享、參考、研究為目的,不存在任何商業目的。其版權屬原作者所有,如有侵權,請與小編聯系!情況屬實本人將予以刪除!

          文章投稿關于web前端網站點搜索站長推薦網站地圖站長QQ:522607023

          小程序專欄: 土味情話心理測試腦筋急轉彎幽默笑話段子句子語錄成語大全

          国产精品高清视频免费 - 视频 - 在线观看 - 影视资讯 - 唯爱网