摘要:本文主要是介紹開(kāi)發(fā)一個(gè)簡(jiǎn)單的腳手架,了解開(kāi)發(fā)的基本流程最終通過(guò)鏈接到全局包。完成之后,就可以把腳手架發(fā)布到上面,通過(guò)進(jìn)行全局安裝,就可以在自己本機(jī)上執(zhí)行來(lái)初始化項(xiàng)目,這樣便完成了一個(gè)簡(jiǎn)單的腳手架工具了。
腳手架,這個(gè)名詞對(duì)于作為前端的我們來(lái)說(shuō),也許并不陌生吧,像vue-cli,react-native-cli等,全局安裝后,只需要在命令行中敲入一個(gè)簡(jiǎn)單的命令,便可幫我們快速的生成一個(gè)初始項(xiàng)目,如vue init webpack projectName,即可生成一個(gè)初始的vue項(xiàng)目。
本文主要是介紹開(kāi)發(fā)一個(gè)簡(jiǎn)單的腳手架,了解開(kāi)發(fā)的基本流程、最終通過(guò)npm link鏈接到全局包。
1、減少時(shí)間,不必從零開(kāi)始搭建初始項(xiàng)目,提高開(kāi)發(fā)效率。
2、便于多人協(xié)作。
3、項(xiàng)目更新同步方便,只需要更新代碼庫(kù)中項(xiàng)目模板,即可下載最新的項(xiàng)目。
在開(kāi)始項(xiàng)目前,先簡(jiǎn)單介紹下node相關(guān)的一些基礎(chǔ)知識(shí),通過(guò)npm init初始化一個(gè)node項(xiàng)目時(shí),會(huì)生成一個(gè)package.json的配置文件,包括項(xiàng)目名稱、版本、作者、依賴等相關(guān)信息,主要說(shuō)一下其中的bin字段。
很多包都有一個(gè)或多個(gè)可執(zhí)行的文件,希望放在PATH中,(實(shí)際上,就是這個(gè)功能讓npm可執(zhí)行的)。
當(dāng)你要用這個(gè)功能時(shí),需要給package.json中的bin字段添加一個(gè)命令名,并指向需要執(zhí)行的文件(即后文的入口文件)。初始化的時(shí)候npm會(huì)將他鏈接到prefix/bin(全局初始化)或者./node_modules/.bin/(本地初始化)。
比如,npm有:
{ "bin" : { "npm" : "./npm-cli.js" } }
所以,當(dāng)你初始化npm,它會(huì)創(chuàng)建一個(gè)符號(hào)鏈接到npm-cli.js腳本到/usr/local/bin/npm。
如果你只有一個(gè)可執(zhí)行文件,并且名字和包名一樣。那么你可以只用一個(gè)字符串,比如:
{ "name": "my-program" , "version": "1.2.5" , "bin": "./path/to/program" }
結(jié)果和這個(gè)一樣:
{ "name": "my-program" , "version": "1.2.5" , "bin" : { "my-program" : "./path/to/program" } }
想要了解package.json更多的詳細(xì)配置,請(qǐng)參考這篇文章
思路要開(kāi)發(fā)腳手架,首先要理清思路,腳手架是如何工作的?我們可以借鑒 vue-cli 的基本思路。vue-cli 是將項(xiàng)目模板放在 git 上,運(yùn)行的時(shí)候再根據(jù)用戶交互下載不同的模板,經(jīng)過(guò)模板引擎渲染出來(lái),生成項(xiàng)目。這樣將模板和腳手架分離,就可以各自維護(hù),即使模板有變動(dòng),只需要上傳最新的模板即可,而不需要用戶去更新腳手架就可以生成最新的項(xiàng)目。那么就可以按照這個(gè)思路來(lái)進(jìn)行開(kāi)發(fā)了。
初始化項(xiàng)目新建一個(gè)文件夾,打開(kāi)命令行工具,通過(guò)npm init 進(jìn)行項(xiàng)目初始化,會(huì)在項(xiàng)目根目錄下生成package.json文件。
npm init安裝依賴
npm install commander download-git-repo inquirer handlebars ora chalk log-symbols shelljs -S
除此之外,還使用了nodejs的幾個(gè)內(nèi)置模塊:fs、path、child_process
commander.js:可以自動(dòng)的解析命令和參數(shù),用于處理用戶輸入的命令。
download-git-repo:下載并提取 git 倉(cāng)庫(kù),用于下載項(xiàng)目模板。
Inquirer.js:通用的命令行用戶界面集合,用于和用戶進(jìn)行交互。
handlebars.js:模板引擎,將用戶提交的信息動(dòng)態(tài)填充到文件中。
ora:下載過(guò)程久的話,可以用于顯示下載中的動(dòng)畫(huà)效果。
chalk:可以給終端的字體加上顏色。
log-symbols:可以在終端上顯示出 √ 或 × 等的圖標(biāo)。
fs:node內(nèi)置的文件處理模塊。
path:node內(nèi)置的路徑處理、解析模塊。
child_process:node中創(chuàng)建子進(jìn)程模塊。
配置入口文件1、在package.json文件中增加bin字段,暫且先命名為okcli吧。
"bin": { "okcli": "./index.js" }
2、在項(xiàng)目根目錄新建index.js文件,在index.js文件頂部添加以下代碼:
#!/usr/bin/env node
即可進(jìn)行開(kāi)發(fā)。
在這里,簡(jiǎn)單介紹下這行代碼含義。
!/usr/bin/node是告訴操作系統(tǒng)執(zhí)行這個(gè)腳本的時(shí)候,調(diào)用/usr/bin下的node解釋器;
!/usr/bin/env node這種用法是為了防止操作系統(tǒng)用戶沒(méi)有將node裝在默認(rèn)的/usr/bin路徑里。當(dāng)系統(tǒng)看到這一行的時(shí)候,首先會(huì)到env設(shè)置里查找node的安裝路徑,再調(diào)用對(duì)應(yīng)路徑下的解釋器程序完成操作。
!/usr/bin/node相當(dāng)于寫(xiě)死了node路徑;
!/usr/bin/env node會(huì)去環(huán)境設(shè)置尋找node目錄,推薦這種寫(xiě)法
const program = require("commander"); const inquirer = require("inquirer"); const symbols = require("log-symbols"); const download = require("download-git-repo"); const handlebars = require("handlebars"); const chalk = require("chalk"); const ora = require("ora"); const shell = require("shelljs"); const child_process = require("child_process"); const fs = require("fs"); const path = require("path"); program.version("1.0.0", "-v, --version") .command("init") .action((name) => { console.log(name); }); program.parse(process.argv);
調(diào)用program.version("1.0.0", "-v, --version")會(huì)將-v和--version添加到命令行中,調(diào)用時(shí)可通過(guò)帶上該參數(shù)獲取該腳手架的版本號(hào)(命令 -v/--version),調(diào)用comand("init
action是執(zhí)行command命令時(shí)發(fā)生的回調(diào),參數(shù)為命令行中輸入的name,即init
現(xiàn)在可以通過(guò)調(diào)用node index.js init test,可以看到控制臺(tái)中已經(jīng)打印了輸入的項(xiàng)目名,也就是test。
其中:program.parse(process.argv)解析命令行中的參數(shù),解析出name,并傳入action回調(diào)。
通過(guò)download-git-repo或者直接使用shelljs或者child_process直接運(yùn)行命令進(jìn)行下載模塊(個(gè)人選擇的是第三種)。
download-git-repo 支持從 Github、Gitlab 和 Bitbucket 下載倉(cāng)庫(kù),各自的具體用法可以參考官方文檔。
download("https://github.com/jefferyE/webpack-configuration-for-vue", name, {clone: true}, (err) => { if(err){ // spinner.fail(); console.log(symbols.error, chalk.red(err)); }else{ // spinner.fail(); } })
或者
if (shell.exec("git clone https://github.com/jefferyE/webpack-configuration-for-vue").code == 0) { // spinner.succeed(); } else { // spinner.fail(); console.log(symbols.error, chalk.red("模板下載失敗")) }
或者
child_process.exec("git clone https://github.com/jefferyE/webpack-configuration-for-vue", function(err, stdout, stderr) { if (err) { // spinner.fail(); console.log(symbols.error, chalk.red("模板下載失敗")) } else { // spinner.succeed(); } })
其中:download() 第一個(gè)參數(shù)就是倉(cāng)庫(kù)地址,但是有一點(diǎn)點(diǎn)不一樣。實(shí)際的倉(cāng)庫(kù)地址是 https://github.com/jefferyE/w... ,可以看到端口號(hào)后面的 ‘/‘ 在參數(shù)中要寫(xiě)成 ‘:’,#master 代表的就是分支名,不同的模板可以放在不同的分支中,更改分支便可以實(shí)現(xiàn)下載不同的模板文件了。第二個(gè)參數(shù)是路徑,上面我們直接在當(dāng)前路徑下創(chuàng)建一個(gè) name 的文件夾存放模板,也可以使用二級(jí)目錄比如 test/${name}
交互命令行命令行交互功能可以在用戶執(zhí)行 init 命令后,向用戶提出問(wèn)題,接收用戶的輸入并作出相應(yīng)的處理。這里使用 inquirer.js 來(lái)實(shí)現(xiàn),也可以自己使用node內(nèi)置的readline模塊。
具體可以參考我的這篇文章
inquirer.prompt([ { type: "input", name: "author", message: "請(qǐng)輸入作者名稱" } ]).then((answers) => { console.log(answers.author); })
通過(guò)這里例子可以看出,問(wèn)題就放在 prompt() 中,問(wèn)題的類型為 input 就是輸入類型,name 就是作為答案對(duì)象中的 key,message 就是問(wèn)題了,用戶輸入的答案就在 answers 中,使用起來(lái)就是這么簡(jiǎn)單。更多的參數(shù)設(shè)置可以參考官方文檔。
渲染package模板這里用 handlebars 的語(yǔ)法對(duì) HTML5/H5Template 倉(cāng)庫(kù)的模板中的 package.json 文件做一些修改。并在下載模板完成之后將用戶輸入的答案渲染到 package.json 中。
{ "name": "{{name}}", "version": "1.0.0", "description": "{{description}}", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "{{author}}", "license": "ISC" }
注意:由于我的項(xiàng)目沒(méi)有更改package模板,因此通過(guò)在下載模板后,解析時(shí)進(jìn)行動(dòng)態(tài)修改的。
除此之外,通過(guò)ora、chalk模塊也進(jìn)行了一些視覺(jué)美化。具體請(qǐng)參考完整代碼。
完整代碼如下:
#!/usr/bin/env node const program = require("commander"); const chalk = require("chalk"); const ora = require("ora"); const fs = require("fs"); const inquirer = require("inquirer"); const shell = require("shelljs"); const symbols = require("log-symbols"); const download = require("download-git-repo"); const child_process = require("child_process"); const handlebars = require("handlebars"); const path = require("path"); program.version("1.0.0", "-v, --version"). command("init"). action(name => { console.log(name); if (!fs.existsSync(name)) { console.log("正在創(chuàng)建項(xiàng)目..."); inquirer.prompt([ { name: "description", message: "請(qǐng)輸入項(xiàng)目描述" }, { name: "author", message: "請(qǐng)輸入作者名稱" } ]).then(answers => { console.log(answers) const spinner = ora("正在向下載模板... "); spinner.start(); child_process.exec("git clone https://github.com/jefferyE/webpack-configuration-for-vue", function(err, stdout, stderr) { if (err) { spinner.fail(); console.log(symbols.error, chalk.red("模板下載失敗")) } else { spinner.succeed(); shell.mv(__dirname + "/webpack-configuration-for-vue", __dirname + "/" + name) const filename = `${name}/package.json`; const meta = { name, description: answers.description, author: answers.author } if (fs.existsSync(filename)) { const content = fs.readFileSync(filename).toString(); let dt = JSON.parse(content); dt.name = "{{name}}"; dt.description = "{{description}}" const result = handlebars.compile(JSON.stringify(dt, null, 2))(meta); fs.writeFileSync(filename, result); console.log(symbols.success, chalk.green("項(xiàng)目初始化完成")); } else { console.log(symbols.error, chalk.red("package不存在")) } } }) }) } else { console.log(symbols.error, chalk.red("項(xiàng)目已存在")); } }) program.parse(process.argv);
其中:
1、在用戶輸入答案之后,開(kāi)始下載模板,這時(shí)候使用 ora 來(lái)提示用戶正在下載中。
2、然后通過(guò) chalk 來(lái)為打印信息加上樣式,比如成功信息為綠色,失敗信息為紅色,這樣子會(huì)讓用戶更加容易分辨,同時(shí)也讓終端的顯示更加的好看。
3、除了給打印信息加上顏色之外,還可以使用 log-symbols 在信息前面加上 √ 或 × 等的圖標(biāo)。
完成之后,就可以把腳手架發(fā)布到 npm 上面,通過(guò) -g 進(jìn)行全局安裝,就可以在自己本機(jī)上執(zhí)行 okcli init [name] 來(lái)初始化項(xiàng)目,這樣便完成了一個(gè)簡(jiǎn)單的腳手架工具了。
鏈接全局命令在根目錄運(yùn)行 npm link命令,將包鏈接到全局環(huán)境。
npm link命令可以將一個(gè)任意位置的npm包鏈接到全局執(zhí)行環(huán)境,從而在任意位置使用命令行都可以直接運(yùn)行該npm包。
具體請(qǐng)參考這篇文章
感謝:
參考文章??文章1
????????????????文章2
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95415.html
摘要:更多資源請(qǐng)文章轉(zhuǎn)自月份前端資源分享的作用數(shù)組元素隨機(jī)化排序算法實(shí)現(xiàn)學(xué)習(xí)筆記數(shù)組隨機(jī)排序個(gè)變態(tài)題解析上個(gè)變態(tài)題解析下中的數(shù)字前端開(kāi)發(fā)筆記本過(guò)目不忘正則表達(dá)式聊一聊前端存儲(chǔ)那些事兒一鍵分享到各種寫(xiě)給剛?cè)腴T(mén)的前端工程師的前后端交互指南物聯(lián)網(wǎng)世界的 更多資源請(qǐng)Star:https://github.com/maidishike... 文章轉(zhuǎn)自:https://github.com/jsfr...
摘要:目前網(wǎng)上關(guān)于插件開(kāi)發(fā)的文章少得可憐,下面分享最近的經(jīng)歷,如何快速上手開(kāi)發(fā)一個(gè)插件。第六步調(diào)試插件在打開(kāi)的網(wǎng)頁(yè)中可以看到工具欄中實(shí)現(xiàn)了插件。 TinyMCE是一個(gè)非常優(yōu)秀的輕量級(jí)的所見(jiàn)即所得HTML編輯器,歷史悠久,開(kāi)源,在github的start也非常高的,且長(zhǎng)期保持更新。TinyMCE的官方插件不少,基本能滿足日常需求,但是有時(shí)候我們還需要一些結(jié)合業(yè)務(wù)的功能。這時(shí)官方插件無(wú)法滿足,就...
摘要:下面來(lái)就來(lái)講講腳手架的安裝吧。如何安裝安裝只需要在終端下輸入下面一條命令自帶不需要安裝安裝完成后使用即可。原因是的問(wèn)題,要求版本是。想用安裝,就必須用安裝一下。 前言 Vue作為前端三大框架(Angular,React,Vue)之一,號(hào)稱是最簡(jiǎn)單,最容易上手的框架,同時(shí)也是行內(nèi)的大趨勢(shì),還可以用來(lái)開(kāi)發(fā)最火的小程序。具有開(kāi)發(fā)快,雙向數(shù)據(jù)流等特點(diǎn),有些人認(rèn)為Vue是Angular和Reac...
摘要:下面來(lái)就來(lái)講講腳手架的安裝吧。如何安裝安裝只需要在終端下輸入下面一條命令自帶不需要安裝安裝完成后使用即可。原因是的問(wèn)題,要求版本是。想用安裝,就必須用安裝一下。 前言 Vue作為前端三大框架(Angular,React,Vue)之一,號(hào)稱是最簡(jiǎn)單,最容易上手的框架,同時(shí)也是行內(nèi)的大趨勢(shì),還可以用來(lái)開(kāi)發(fā)最火的小程序。具有開(kāi)發(fā)快,雙向數(shù)據(jù)流等特點(diǎn),有些人認(rèn)為Vue是Angular和Reac...
閱讀 1083·2021-11-16 11:45
閱讀 2731·2021-09-27 13:59
閱讀 1327·2021-08-31 09:38
閱讀 3158·2019-08-30 15:52
閱讀 1323·2019-08-29 13:46
閱讀 2095·2019-08-29 11:23
閱讀 1654·2019-08-26 13:47
閱讀 2502·2019-08-26 11:54