node命令行工具之實(shí)現(xiàn)項(xiàng)目工程自動(dòng)初始化的標(biāo)準(zhǔn)流程
一、目的
傳統(tǒng)的前端項(xiàng)目初始流程一般是這樣:
可以看出,傳統(tǒng)的初始化步驟,花費(fèi)的時(shí)間并不少。而且,人工操作的情況下,總有改漏的情況出現(xiàn)。這個(gè)缺點(diǎn)有時(shí)很致命。
甚至有馬大哈,沒(méi)有更新項(xiàng)目倉(cāng)庫(kù)地址,導(dǎo)致提交代碼到舊倉(cāng)庫(kù),這就很尷尬了。。。
基于這些情況,編寫命令行工具(CLI)的目的就很明確:
用于新項(xiàng)目工程的初始化利用工具進(jìn)行初始化,可以節(jié)省項(xiàng)目初期的準(zhǔn)備時(shí)間避免出現(xiàn)改漏的情況杜絕未更新項(xiàng)目版本倉(cāng)庫(kù)地址的問(wèn)題
以下是新的流程示意圖:
二、自動(dòng)化流程分析
以下是自動(dòng)化流程圖:
從流程圖可以得出兩個(gè)重要的信息:
配置信息模板文件
命令行工具的角色,是負(fù)責(zé)將兩個(gè)信息進(jìn)行融合,提供一個(gè)交互平臺(tái)給用戶。
三、工具準(zhǔn)備
3.1 配置信息工具
配置信息的獲得,需要靠和用戶進(jìn)行交互。由于程序員一般是用終端輸入命令進(jìn)行項(xiàng)目操作。所以,這里選擇了兩個(gè)工具進(jìn)行支撐。
commander
借鑒Ruby commander理念實(shí)現(xiàn)的命令行執(zhí)行補(bǔ)全解決方案
commander
可以接收命令行傳入的參數(shù)
例子:
npg-cli --help ♫ ♫♬♪♫ npm-package-cli ♫ ♫♬♪♫ Usage: npg-cli [options] Options: -V, --version output the version number -h, --help output usage information run testcli and edit the setting.
inquirer
常用交互式命令行用戶界面的集合。
inquirer
用詢問(wèn)式的語(yǔ)句,與用戶進(jìn)行交互,接收參數(shù)
例子:
npg-cli ♫ ♫♬♪♫ npm-package-cli ♫ ♫♬♪♫ Follow the prompts to complete the project configuration. ? project name test ? version 1.0.0 ? description
3.2 模板信息工具
前端的JavaScript 模板引擎,比如ejs,jade等??梢愿鶕?jù)傳入的參數(shù),對(duì)模板標(biāo)簽進(jìn)行替換,最終生成html。
如果把所有項(xiàng)目文件,不管文件后綴名,都看成是ejs模板,則可以在文件內(nèi)容中使用ejs語(yǔ)法。
再根據(jù)配置信息進(jìn)行替換,最終生成新文件。
其實(shí),業(yè)界依據(jù)這個(gè)想法,已經(jīng)有成熟的工具產(chǎn)生。
mem-fs
mem-fs
是對(duì)文件進(jìn)行讀取,存入內(nèi)存中。
mem-fs-editor
mem-fs-editor
是對(duì)內(nèi)存中的文件信息,使用ejs語(yǔ)法進(jìn)行編譯。最后調(diào)用commit
方法輸出最終文件。
3.3 提示信息工具
提示信息,除了console.log
,還可以使用色彩更豐富的chalk
。
這樣,可以輸出更直觀、友好的提示。
3.4 文件操作
文件操作,有業(yè)界成熟的shelljs
。
利用shelljs
,可以在項(xiàng)目中簡(jiǎn)化以下步驟:
一些項(xiàng)目文件,不需要修改,只用直接copy??梢允褂?code>shelljs.copySync同步方式生成。一些文件夾,需要提前構(gòu)建,可以使用shelljs.mkdir
進(jìn)行創(chuàng)建
四、實(shí)現(xiàn)
以下按我做的開源項(xiàng)目——npm-package-cli
的創(chuàng)作過(guò)程進(jìn)行分拆、講解。
4.1 初始化
新建項(xiàng)目文件夾npm-package-cli
,并在該文件夾下運(yùn)行npm init
,生成package.json
。
項(xiàng)目結(jié)構(gòu)如下:
npm-package-cli |-- package.json
4.2 生成全局指令
這里要生成的全局指令是npg-cli
。
4.2.1 新建執(zhí)行文件
新建文件夾bin
,并在文件夾下新建名稱為cli
的shell腳本文件(注意:不能有后綴名)。
cli
shell腳本文件內(nèi)容如下:
#!/usr/bin/env node console.log('hello world');
其中,#!/usr/bin/env node
是告訴編譯器,以node
的方式,運(yùn)行代碼。
并在package.json
加入以下內(nèi)容:
"bin": { "npg-cli": "bin/cli" }
此時(shí),項(xiàng)目結(jié)構(gòu)如下:
npm-package-cli |-- bin |-- cli |-- package.json
4.2.2 鏈接指令到全局
鏈接指令有兩種方式:
npm link
npm install -g
兩種方式,都需要在npm-package-cli
文件夾下運(yùn)行,才能生效。
作用是把npg-cli
指令,指向全局的bin
文件下,實(shí)現(xiàn)軟鏈。
4.2.3 運(yùn)行
在任意文件夾下運(yùn)行命令:
npg-cli # 輸出 hello world
到這里,一個(gè)基本的指令就算完成了,接下來(lái)是指令的工作內(nèi)容細(xì)化。
4.3 初始化操作類Creation
Creation
的作用是整合所有操作,并提供接口給指令文件cli
。
Creation
的結(jié)構(gòu)如下:
class Creation{ constructor(){ // code } do(){ // code } // other function }
其中do
方法暴露給腳本文件cli
調(diào)用。
Creation
類放在src/index.js
中。
此時(shí),項(xiàng)目結(jié)構(gòu)如下:
npm-package-cli |-- bin |-- cli |-- src |-- index.js |-- package.json
4.4 修改cli
文件
#!/usr/bin/env node const Creator = require('../src/index.js'); const project = new Creator(); project.do();
這樣,只要實(shí)現(xiàn)好do
方法,就可以完成npg-cli
指令的運(yùn)行了。
4.5 實(shí)現(xiàn)命令行參數(shù)讀取
實(shí)現(xiàn)npg-cli --help
,需要借助上文提到的工具commander
。
新建src/command.js
文件,文件內(nèi)容如下:
const commander = require('commander'); const chalk = require('chalk'); const packageJson = require('../package.json'); const log = console.log; function initCommand(){ commander.version(packageJson.version) .on('--help', ()=>{ log(chalk.green(' run testcli and edit the setting.')); }) .parse(process.argv); } module.exports = initCommand;
此時(shí),項(xiàng)目結(jié)構(gòu)如下:
npm-package-cli |-- bin |-- cli |-- src |-- command.js |-- index.js |-- package.json
然后在Creation.do
方法內(nèi)執(zhí)行initCommand()
即可生效。
// src/index.js Creation const initCommand = require('./command'); class Creation{ // other code do(){ initCommand(); } }
此時(shí),運(yùn)行npg-cli --help
指令,就可以看到:
Usage: npg-cli [options] Options: -V, --version output the version number -h, --help output usage information run testcli and edit the setting.
4.6 獲取用戶輸入配置信息
要獲取用戶輸入的信息,需要借助工具inquirer
。
新建src/setting.js
文件,文件內(nèi)容如下:
const inquirer = require('inquirer'); const fse = require('fs-extra'); function initSetting(){ let prompt = [ { type: 'input', name: 'projectName', message: 'project name', validate(input){ if(!input){ return 'project name is required.' } if(fse.existsSync(input)){ return 'project name of folder is exist.' } return true; } }, // other prompt ]; return inquirer.prompt(prompt); } module.exports = initSetting;
此時(shí),項(xiàng)目結(jié)構(gòu)如下:
npm-package-cli |-- bin |-- cli |-- src |-- command.js |-- index.js |-- setting.js |-- package.json
然后在Creation.do
方法內(nèi)執(zhí)行initSetting()
即可生效。
// src/index.js Creation const initCommand = require('./command'); const initSetting = require('./setting'); class Creation{ // other code do(){ initCommand(); initSetting().then(setting => { // 用戶輸入完成后,會(huì)得到全部輸入信息的json數(shù)據(jù) setting }); } }
這里,inquirer.prompt
方法裝載好要收集的問(wèn)題后,返回的是Promise
對(duì)象。收集完成之后,要在then
方法內(nèi)拿到配置信息,以便進(jìn)行下一步模板替換的操作。
4.7 模板文件替換輸出
模板文件替換,要用到工具mem-fs
和mem-fs-editor
。
文件操作,要用到工具shelljs
。
新建src/output.js
文件,文件內(nèi)容如下(刪除了部分代碼,以下只是示例,完整項(xiàng)目看最后分享鏈接):
const chalk = require('chalk'); const fse = require('fs-extra'); const path = require('path'); const log = console.log; function output(creation){ return new Promise((resolve, reject)=>{ // 拿到配置信息 const setting = creation._setting; const { projectName } = setting; // 獲取當(dāng)前命令行執(zhí)行環(huán)境所在文件夾 const cwd = process.cwd(); // 初始化文件夾path const projectPath = path.join(cwd, projectName); const projectResolve = getProjectResolve(projectPath); // 新建項(xiàng)目文件夾 fse.mkdirSync(projectPath); // copy文件夾 creation.copy('src', projectResolve('src')); // 根據(jù)配置信息,替換文件內(nèi)容 creation.copyTpl('package.json', projectResolve('package.json'), setting); // 將內(nèi)存中的文件,輸出到硬盤上 creation._mfs.commit(() => { resolve(); }); }); } module.exports = output;
output方法的作用:
- 新建項(xiàng)目文件夾
- 把模板文件讀取出來(lái),根據(jù)配置信息,進(jìn)行替換(調(diào)用的是mem-fs-editor的copyTpl方法)
- 拷貝其他文件
- 輸出最終文件到硬盤上
這里最重要的一步,是調(diào)用mem-fs-editor
的方法后,要執(zhí)行mem-fs-editor
的commit
方法,輸出內(nèi)存中的文件到硬盤上。
在Creation.do方法中,調(diào)用output方法即可輸出新項(xiàng)目文件。
打開src/index.js文件,文件內(nèi)容增加如下方法:
// src/index.js Creation const initCommand = require('./command'); const initSetting = require('./setting'); const output = require('./output'); class Creation{ // other code do(){ initCommand(); initSetting().then(setting => { // 用戶輸入完成后,會(huì)得到全部輸入信息的json數(shù)據(jù) setting this._setting = Object.assign({}, this._setting, setting); // 輸出文件 output(this).then(res => { // 項(xiàng)目輸出完成 }); }); } }
4.8 階段小結(jié)
自動(dòng)初始化一個(gè)項(xiàng)目的流程不外乎以下三點(diǎn):
- 讀取用戶配置
- 讀取模板文件
- 根據(jù)配置,編譯模板文件,輸出最終文件
命令行工具,是對(duì)這三點(diǎn)的有效整合,串連成一個(gè)規(guī)范的流程。
五、發(fā)布npm包的注意點(diǎn)
命令行工具中,使用的第三方工具包,都需要用--save的方式安裝。
體現(xiàn)在package.json
的表現(xiàn)是dependencies
字段:
"dependencies": { "chalk": "^2.4.2", "commander": "^3.0.0", "fs-extra": "^8.1.0", "inquirer": "^6.5.0", "mem-fs": "^1.1.3", "mem-fs-editor": "^6.0.0", "shelljs": "^0.8.3" },
這樣,其他用戶在安裝你發(fā)布的CLI工具時(shí),才會(huì)自動(dòng)安裝這些依賴。
六、項(xiàng)目開源
我創(chuàng)作的npm-package-cli
,是專門用于生成個(gè)人npm package
項(xiàng)目的CLI工具。
生成的項(xiàng)目,囊括以下功能點(diǎn):
- 支持TypeScrpt
- mocha+chai自動(dòng)化測(cè)試,支持使用TypeScript編寫測(cè)試用例支持測(cè)試覆蓋率
- coverage支持eslint,包括對(duì)TypeScript的lint檢查
- Git commit規(guī)范提交
- Git版本自動(dòng)打標(biāo)簽(standard-version),更新CHANGELOG.md
- 輸出的npm包
支持各種模塊規(guī)范(AMD、CMD、CommonJS、ESModule)
CLI工具安裝方式:
npm install -g npm-package-cli
開源倉(cāng)庫(kù)地址:https://github.com/wall-wxk/npm-package-cli
如果對(duì)你有所幫助,麻煩給個(gè)Star,你的肯定是我前進(jìn)的動(dòng)力~
總結(jié)
以上所述是小編給大家介紹的node命令行工具之實(shí)現(xiàn)項(xiàng)目工程自動(dòng)初始化的標(biāo)準(zhǔn)流程,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
如果你覺得本文對(duì)你有幫助,歡迎轉(zhuǎn)載,煩請(qǐng)注明出處,謝謝!
- node.js利用express自動(dòng)搭建項(xiàng)目的全過(guò)程
- node koa2 ssr項(xiàng)目搭建的方法步驟
- nodeJs項(xiàng)目在阿里云的簡(jiǎn)單部署
- 云服務(wù)器部署Node.js項(xiàng)目的方法步驟(小白系列)
- node創(chuàng)建Vue項(xiàng)目步驟詳解
- nodejs對(duì)項(xiàng)目下所有空文件夾創(chuàng)建gitkeep的方法
- 從0到1構(gòu)建vueSSR項(xiàng)目之node以及vue-cli3的配置
- PHPStorm中如何對(duì)nodejs項(xiàng)目進(jìn)行單元測(cè)試詳解
- 使用pm2自動(dòng)化部署node項(xiàng)目的方法步驟
- 為什么node.js不適合大型項(xiàng)目
相關(guān)文章
詳解基于Node.js的HTTP/2 Server實(shí)踐
HTTP/2目前已經(jīng)逐漸的在各大網(wǎng)站上開始使用,這篇文章主要介紹了詳解基于Node.js的HTTP/2 Server實(shí)踐,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05node.js 利用流實(shí)現(xiàn)讀寫同步,邊讀邊寫的方法
下面小編就為大家?guī)?lái)一篇node.js 利用流實(shí)現(xiàn)讀寫同步,邊讀邊寫的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09NodeJS和BootStrap分頁(yè)效果的實(shí)現(xiàn)代碼
這篇文章主要介紹了NodeJS和BootStrap分頁(yè)效果的實(shí)現(xiàn)代碼的相關(guān)資料,非常不錯(cuò)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-11-11Express框架實(shí)現(xiàn)簡(jiǎn)單攔截器功能示例
這篇文章主要介紹了Express框架實(shí)現(xiàn)簡(jiǎn)單攔截器功能,結(jié)合實(shí)例形式分析了express框架攔截器相關(guān)功能與使用方法,需要的朋友可以參考下2023-05-05node+multer實(shí)現(xiàn)圖片上傳的示例代碼
這篇文章主要介紹了node+multer實(shí)現(xiàn)圖片上傳的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02