成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從零實現命令行腳手架工具——自動初始化項目工程以及發布到NPM

開發 開發工具
這篇文章將帶你從零實現一款命令行腳手架工具用于初始化項目以及如何發布到NPM。那么,這么方便的命令行工具是怎么實現的呢?下面我們就開始進入實戰環節。

[[418135]]

前言

這篇文章將帶你從零實現一款命令行腳手架工具用于初始化項目以及如何發布到NPM。首先,我們所熟知的VueCLI就是采用命令行工具快速生成項目工程目錄的,這樣,我們每次開發項目前只需要在命令行中輸入命令,然后就可以快速生成項目工程,非常方便。那么,這么方便的命令行工具是怎么實現的呢?下面我們就開始進入實戰環節。

實戰

我將會使用之前自己開發的一款腳手架工具strview-cli來介紹如何實現它的。這個腳手架工具的源碼地址如下:

  1. https://github.com/maomincoding/strview-cli 

第一步

首先,我們姑且創建一個文件夾名字叫strviewCli。

  1. mkdir strviewCli 

然后,在文件夾中初始化項目

  1. npm init 

之后,自動生成一個package.json文件。

第二步

我們再創建一個文件夾,即bin。

  1. mkdir bin 

接著,在文件夾中我們創建一個index.js文件、config文件夾、utils文件夾。

  1. touch index.js 
  2. mkdir config 
  3. mkdir utils 

最后,在config 文件中創建一個index.js文件,在utils文件夾中創建一個checkDire.js。

  1. touch index.js 
  2. touch checkDire.js 

目前,我們文件目錄結構為

  1. - bin 
  2.  -- config 
  3.   --- index.js 
  4.  -- utils 
  5.   --- checkDire.js 
  6.  -- index.js 
  7. - package.json 

最后的最后,我們在根目錄下,創建一個.gitignore文件,以及README.md。

最后,命令行工具項目文件目錄如下:

  1. - bin 
  2.  -- config 
  3.   --- index.js 
  4.  -- utils 
  5.   --- checkDire.js 
  6.  -- index.js 
  7. - package.json 
  8. - README.md 
  9. - .gitignore 

第三步

上面兩步,我們給我們的命令行工具奠定了基本結構。下面,我們將在一一為每個文件注入靈魂~

首先,.gitignore文件和README.md,這里就不過多闡述了,可以根據自己的需要進行增添內容。

其次,詳細介紹的就是package.json文件。以下是我自己寫的package.json,這里需要注意幾個重要的字段。

  • name :項目名
  • version:版本號
  • description:項目描述
  • main:入口文件
  • author:作者
  • keywords:關鍵詞
  • bin:腳本執行入口
  • repository:代碼倉庫
  • license:許可證
  • private:私有
  • dependencies:依賴
  • browserslist:指定了項目的目標瀏覽器的范圍
  1.   "name""strview-cli"
  2.   "version""1.1.1"
  3.   "description""Strview.js project scaffolding tools."
  4.   "main""index.js"
  5.   "author": { 
  6.   "name""maomincoding"
  7.   "email""17864296568@163.com"
  8.   "url""https://www.maomin.club" 
  9.    }, 
  10.   "keywords": [ 
  11.  "strview"
  12.     "strview.js"
  13.     "strview-app"
  14.     "strview-cli" 
  15.  ], 
  16.   "bin": { 
  17.   "strview-cli""./bin/index.js" 
  18.  }, 
  19.   "repository": { 
  20.   "type""git"
  21.   "url""https://github.com/maomincoding/strview-cli.git" 
  22.  }, 
  23.   "license""MIT"
  24.   "private"false
  25.   "dependencies": { 
  26.   "chalk""^4.0.0"
  27.   "commander""^5.0.0"
  28.   "fs-extra""^9.0.0"
  29.   "inquirer""^7.1.0" 
  30.     }, 
  31.  "browserslist": [ 
  32.   "> 1%"
  33.   "last 2 versions" 
  34.  ] 

上面的package.json中幾個屬性如:name、version、description、main、author、keywords、repository、license可以根據自己的需求來定義。

你可能會看到dependencies屬性中有幾個依賴,分別是chalk、commander、fs-extra、inquirer。這里先提一下,下面會詳細介紹它們。不過,需要注意的是fs-extra模塊是添加了本機fs模塊中不包含的文件系統方法,并向fs方法添加了promise支持。它還使用優美的fs來防止EMFILE錯誤。它應該是fs的替代品。

第四步

接下來,我們將進入bin文件夾中,然后,我們首先需要編輯config\index.js文件。

  1. module.exports = { 
  2.  npmUrl: 'https://registry.npmjs.org/strview-cli'
  3.  promptTypeList: [ 
  4.   { 
  5.    type: 'list'
  6.    message: 'Please select the template type to pull:'
  7.    name'type'
  8.    choices: [ 
  9.     { 
  10.      name'strview-app'
  11.      value: { 
  12.       url: 'https://github.com/maomincoding/strview-app.git'
  13.       gitName: 'strview-app'
  14.       val: 'strview-app'
  15.      }, 
  16.     }, 
  17.    ], 
  18.   }, 
  19.  ], 
  20. }; 

以上代碼中導出一個對象,對象中有兩個屬性:npmUrl和promptTypeList。

npmUrl屬性是命令行工具提交到NPM的地址。怎么得到這個地址呢?你需要按照下面步驟:

登錄NPM

  1. npm login 

依次輸入你的用戶名、密碼、郵箱。

發布到NPM

  1. npm publish 

發布成功后,會顯示版本號。記住,每次發布都要更改版本號,否則會出錯。

正常發布之后,你可以打開NPM網址,搜索你的命令行工具的名稱。比如我的命令行工具strview-cli。網址即:https://registry.npmjs.org/strview-cli。

promptTypeList屬性中有一個choices屬性,它是一個數組,你可以配置你遠程項目工程倉庫。數組每個元素是一個對象,比如這里的

  1.  name'strview-app'
  2.  value: { 
  3.    url: 'https://github.com/maomincoding/strview-app.git'
  4.    gitName: 'strview-app'
  5.    val: 'strview-app'
  6.   }, 

name屬性是你的項目工程名稱,value屬性又是一個對象,里面有三個屬性:url、gitName、val分別表示遠程倉庫地址、倉庫名、值(一般與倉庫名一致)。你可以根據你的需要進行配置,這里是我配置的自己的strview-app。

以上就是config\index.js文件的配置。

第五步

下面,我們還在bin文件夾中,我們接下來編輯utils\checkDire.js文件。

  1. const fs = require("fs"); 
  2. const chalk = require("chalk"); 
  3.  
  4. module.exports = function (dir, name) { 
  5.   let isExists = fs.existsSync(dir); 
  6.   if (isExists) { 
  7.     console.log( 
  8.       chalk.red( 
  9.         `The ${name} project already exists in  directory. Please try to use another projectName` 
  10.       ) 
  11.     ); 
  12.     process.exit(1); 
  13.   } 
  14. }; 

這個文件沒有自定義的部分,你只需要直接用即可。這里我們看到引入兩個模塊,分別是fs、chalk。Node.js內置的fs模塊就是文件系統模塊,負責讀寫文件。chalk模塊是美化命令行輸出樣式,使輸出命令不再單調。

我們看到這里導出一個函數,函數有兩個參數:分別是dir和name。我們這里先暫且不看這個函數,先只知道需要傳兩個參數就可以。

第六步

下面我們先分析bin\index.js文件,這個文件是命令行工具的入口文件,非常重要。同樣,這里不需要自定義,直接用就可以。

  1. #!/usr/bin/env node 
  2.  
  3. const fs = require('fs'); 
  4. const path = require('path'); 
  5. const chalk = require('chalk'); 
  6. const commander = require('commander'); 
  7. const inquirer = require('inquirer'); 
  8. const checkDire = require('./utils/checkDire.js'); 
  9. const { exec } = require('child_process'); 
  10. const { version } = require('../package.json'); 
  11. const { promptTypeList } = require('./config'); 
  12.  
  13. commander 
  14.  .version(version, '-v, --version'
  15.  .command('init <projectName>'
  16.  .alias('i'
  17.  .description('Enter the project name and initialize the project template'
  18.  .action(async (projectName) => { 
  19.   await checkDire(path.join(process.cwd(), projectName), projectName); 
  20.   inquirer.prompt(promptTypeList).then((result) => { 
  21.    const { url, gitName, val } = result.type; 
  22.    console.log( 
  23.     'The template type information you selected is as follows:' + val 
  24.    ); 
  25.    console.log('Project initialization copy acquisition...'); 
  26.    if (!url) { 
  27.     console.log( 
  28.      chalk.red(`${val} This type is not supported at the moment...`) 
  29.     ); 
  30.     process.exit(1); 
  31.    } 
  32.    exec('git clone ' + url, function (error, stdout, stderr) { 
  33.     if (error !== null) { 
  34.      console.log(chalk.red(`clone fail,${error}`)); 
  35.      return
  36.     } 
  37.     fs.rename(gitName, projectName, (err) => { 
  38.      if (err) { 
  39.       exec('rm -rf ' + gitName, function (err, out) { }); 
  40.       console.log( 
  41.        chalk.red(`The ${projectName} project template already exist`) 
  42.       ); 
  43.      } else { 
  44.       if (fs.existsSync(`./${projectName}/.git/config`)) { 
  45.        exec('git remote rm origin', { cwd: `./${projectName}` }); 
  46.        console.log( 
  47.         chalk.green( 
  48.          `✔ The ${projectName} project template successfully create
  49.         ) 
  50.        ); 
  51.       } 
  52.      } 
  53.     }); 
  54.    }); 
  55.   }); 
  56.  }); 
  57.  
  58. commander.parse(process.argv); 

我們從頭開始看,我們會看到引入了fs、path、chalk、commander、inquirer、child_process。

path 模塊提供了用于處理文件和目錄的路徑的實用工具。

commander是完整的 node.js 命令行解決方案,它有很多用法,具體你可以參照Commander中文文檔:

  1. https://github.com/tj/commander.js/blob/master/Readme_zh-CN.md 

inquirer是通用交互式命令行用戶界面的集合。開始通過npm init創建package.json文件的時候就有大量與用戶的交互,而現在大多數工程都是通過腳手架來創建的,使用腳手架的時候最明顯的就是與命令行的交互,如果想自己做一個腳手架或者在某些時候要與用戶進行交互,這個時候就不得不提到inquirer.js了。

child_process模塊是nodejs的一個子進程模塊,可以用來創建一個子進程,并執行一些任務。比如說就可以直接在js里面調用shell命令。

介紹完引入的模塊,然后再介紹下面的代碼。你會看到下面的代碼大部分都用到了commander的方法。

首先,commander.version(version, '-v, --version'),.version()方法可以設置版本,之后就可以使用-v或--version命令查看版本。

通過 .command('init ') 可以配置命令。這里的意思是初始化你的項目名稱,你可以根據自己的需求設置。也可以使用.alias('i')簡寫初始化配置命令,原來npm init ,現在也可以使用npm i 命令。

.description('Enter the project name and initialize the project template')這行代碼中.description方法則是對上面初始化配置項目名的描述。

.action((projectName, cmd) => {...})這行代碼中.action方法是定義命令的回調函數,我們發現它使用了async/await這組關鍵字用來處理異步。首先,await checkDire(path.join(process.cwd(), projectName), projectName);傳入兩個參數分別為項目所在的目錄、項目名稱。我們這里先分析checkDire方法,也就是之前utils\checkDire.js文件內的方法。

  1. module.exports = function (dir, name) { 
  2.   let isExists = fs.existsSync(dir); 
  3.   if (isExists) { 
  4.     console.log( 
  5.       chalk.red( 
  6.         `The ${name} project already exists in  directory. Please try to use another projectName` 
  7.       ) 
  8.     ); 
  9.     process.exit(1); 
  10.   } 
  11. }; 

fs.existsSync(dir)以同步的方法檢測目錄是否存在。如果目錄存在 返回 true ,如果目錄不存在 返回false。如果存在了,就執行下面的提示并退出終止進程。

接著,我們又回到bin\index.js文件。接著往下執行,到了inquirer.prompt()這個方法,這個方法的作用主要是啟動提示界面(查詢會話),第一個參數是包含問題對象的問題(數組)(使用反應式接口,還可以傳遞一個Rx.Observable實例),這里我們傳入的是config\index.js文件中的promptTypeList屬性,它是一個數組。

  1. promptTypeList: [ 
  2.  { 
  3.   type: 'list'
  4.   message: 'Please select the template type to pull:'
  5.   name'type'
  6.   choices: [ 
  7.    { 
  8.     name'strview-app'
  9.     value: { 
  10.      url: 'https://github.com/maomincoding/strview-app.git'
  11.      gitName: 'strview-app'
  12.      val: 'strview-app'
  13.     }, 
  14.    }, 
  15.   ], 
  16.  }, 
  17. ], 

inquirer.prompt()這個方法返回一個Promise對象,所以這里可以then()方法來獲取返回的數據。然后我們通過解構來分別獲取到url、gitName、val這三個屬性值。

  1. const { url, gitName, val } = result.type; 

然后,下面就是輸出命令以及執行命令的環節了。我分為兩部分來分析剩余代碼,第一部分如下:

  1. console.log('The template type information you selected is as follows:' + val); 
  2. console.log('Project initialization copy acquisition...'); 
  3.  
  4. if (!url) { 
  5.  console.log(chalk.red(`${val} This type is not supported at the moment...`)); 
  6.  process.exit(1); 

我們這里有一個判斷語句,就是判斷遠程倉庫地址是否是假值,如果是假值的話,就執行提示并退出終止進程。

接著,我們分析第二部分:

  1. exec('git clone ' + url, function (error, stdout, stderr) { 
  2.  if (error !== null) { 
  3.   console.log(chalk.red(`clone fail,${error}`)); 
  4.   return
  5.  } 
  6.  fs.rename(gitName, projectName, (err) => { 
  7.   if (err) { 
  8.    exec('rm -rf ' + gitName, function (err, out) { }); 
  9.    console.log(chalk.red(`The ${projectName} project template already exist`)); 
  10.   } else { 
  11.    if (fs.existsSync(`./${projectName}/.git/config`)) { 
  12.     exec('git remote rm origin', { cwd: `./${projectName}` }); 
  13.     console.log( 
  14.      chalk.green(`✔ The ${projectName} project template successfully create`) 
  15.     ); 
  16.    } 
  17.    } 
  18.  }); 

這部分主要是執行命令,也是最關鍵的部分。這部分首先使用了exec()方法,第一個參數是要執行的命令,第二個參數是回調函數。

首先,我們執行exec('git clone ' + url)來下載遠程項目,接著我們進入回調函數,如果有錯誤,就輸出提示并退出。否則,將使用fs.rename()方法將文件重命名。因為我們下載的遠程倉庫名不一定跟我們初始化配置的名字一樣。

如果錯誤,就刪除遠程項目工程目錄。否則,就判斷./${projectName}/.git/config文件是否存在,如果存在就執行exec('git remote rm origin', { cwd:./${projectName}});命令刪除遠程倉庫地址。這是因為需要自定義配置倉庫地址,而不是直接使用下載的倉庫地址。最后,提示創建成功。

最后一行。commander.parse(process.argv);這行代碼中.parse()的第一個參數是要解析的字符串數組,也可以省略參數而使用process.argv。指明,按 node 約定。

第七步

到了這一步,所有配置文件都配置完成了。如果你想開源的話,你可以參照線上自己生成一個LICENSE文件。這個文件是軟件許可證,可以去github去自動生成這個文件。

最后,我們就要發布我們這個命令行工具了。注意,在發布之前,需要改一下你的版本號。 如之前是1.0.0,現在可以改成2.0.0。具體這三個數字怎么定義,也有說法。第一部分為主版本號,變化了表示有了一個不兼容上個版本的大更改。第二部分為次版本號,變化了表示增加了新功能,并且可以向后兼容。第三部分為修訂版本號,變化了表示有bug修復,并且可以向后兼容。

  1. npm publish 

發布成功。

第八步

這里以strview-cli為例。

你可以全局安裝你的腳手架。

  1. npm i strview-cli -g 

安裝完成之后,你可以查看版本。

  1. strview-cli -v 

最后,就是初始化項目了, 是自定義項目名稱。  

  1. strview-cli init <projectName> 

or 

  1. strview-cli i <projectName> 

結語

謝謝閱讀,希望沒有耽誤你的時間。

你可以自己封裝一個常用的項目工程,可以通過這種方式來初始化你的項目。這樣,才會顯得有逼格!!!哈哈哈~

本文轉載自微信公眾號「前端歷劫之路」,可以通過以下二維碼關注。轉載本文請聯系前端歷劫之路公眾號。

 

責任編輯:武曉燕 來源: 前端歷劫之路
相關推薦

2021-12-19 07:22:16

Create前端工具

2021-04-28 16:10:48

開發腳手架 Spring

2021-05-13 17:02:38

MDC腳手架日志

2020-08-19 08:55:47

Redis緩存數據庫

2022-04-24 11:33:47

代碼管理工程

2021-11-08 09:35:09

Vue代碼前端

2019-06-10 15:00:27

node命令行前端

2021-05-21 05:22:52

腳手架工具項目

2016-08-10 14:59:41

前端Javascript工具

2021-09-01 10:07:43

開發零搭建Groovy

2021-07-13 18:42:38

Spring Boot腳手架開發

2021-04-13 14:47:53

認證授權Java

2021-03-09 17:11:09

數據庫腳手架開發

2020-12-10 16:16:08

工具代碼開發

2020-12-11 06:44:16

命令行工具開發

2017-07-21 09:56:46

Webpack3 Vue.js腳手架

2021-04-20 19:24:16

腳手架 Java微信

2020-06-29 11:35:02

Spring BootJava腳手架

2021-12-23 10:35:32

SpringCloud腳手架架構

2021-04-25 05:31:33

React.js項目FastReactAp
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 香蕉久久久 | 日本午夜精品 | 国产一级网站 | 国产999精品久久久久久绿帽 | 欧美国产一区二区 | 成人免费视频 | 男人的天堂中文字幕 | 亚洲精品久久久久久久久久久久久 | 国产一区二区 | 丁香五月网久久综合 | 亚洲男女视频在线观看 | 狠狠的干 | 亚洲国产成人在线 | 精品视频在线免费观看 | 很黄很污的网站 | 日韩久久久一区二区 | www.日本三级| 日韩精品成人 | 亚洲精品国产成人 | 欧美在线视频一区 | 色视频网站在线观看 | 超碰520| 在线欧美一区 | 国产高清在线视频 | 香蕉视频1024 | 亚洲成人国产精品 | 亚洲精品视频导航 | 亚洲第一区国产精品 | 91视频网| 国产精品久久久久一区二区三区 | 天天摸天天干 | 中文欧美日韩 | 成人特级毛片 | 国产一区二区三区在线 | 亚洲天堂一区 | 亚洲精品在线观 | 久久国产精品久久久久久久久久 | 久久综合狠狠综合久久 | 欧美一级欧美三级在线观看 | 国产区在线观看 | 视频一区二区中文字幕日韩 |