小編給大家分享一下仿vue-cli如何搭建屬于自己的腳手架,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
成都創(chuàng)新互聯(lián)成都網(wǎng)站建設(shè)按需搭建網(wǎng)站,是成都網(wǎng)站建設(shè)公司,為成都花箱提供網(wǎng)站建設(shè)服務(wù),有成熟的網(wǎng)站定制合作流程,提供網(wǎng)站定制設(shè)計(jì)服務(wù):原型圖制作、網(wǎng)站創(chuàng)意設(shè)計(jì)、前端HTML5制作、后臺(tái)程序開發(fā)等。成都網(wǎng)站改版熱線:13518219792
腳手架是啥
從前我總覺(jué)得腳手架是個(gè)很高大上的東西,好像得牛叉:ox:一點(diǎn)的人才寫的出來(lái),可望而不可即。其實(shí)并不是因?yàn)槔щy使我們放棄,而是因?yàn)榉艞壊棚@得困難(這是個(gè)好詞好句:see_no_evil:)。只要你肯花個(gè)一天半天的時(shí)間:fist:,也能寫出屬于你自己的腳手架。
早前腳手架這個(gè)詞是從 vue-cli 這里認(rèn)識(shí)的,我們通過(guò) npm install -g vue-cli
命令全局安裝腳手架后, 再執(zhí)行 vue init webpack project-name
就能初始化好一個(gè)自己的項(xiàng)目,真是尼瑪?shù)纳衿?hushed:。但你有沒(méi)有想過(guò)為什么我們執(zhí)行 vue init
這個(gè)命令就能有個(gè)自己的項(xiàng)目呢。今天,就讓我們一起來(lái)揭開廬山真面目吧!
等等:hand:,扯了一堆,你好像還沒(méi)說(shuō)下啥是腳手架?emmm... 它就是個(gè)工具,方便我們新建項(xiàng)目用的,有了這個(gè)項(xiàng)目我們就能直接開發(fā)了。其實(shí)我們本可以用 git clone url
來(lái)新建(復(fù)制)項(xiàng)目,再 cuo 一點(diǎn)的方法就是復(fù)制粘貼整個(gè)文件夾,一樣也能達(dá)到初始化的目的。腳手架的本質(zhì)也是從遠(yuǎn)程下載一個(gè)模板來(lái)進(jìn)行一個(gè)新項(xiàng)目。額。所以。。。有什么不同呢?就高大上啊:anguished:。當(dāng)然不止于此啦,腳手架可是高級(jí)版的克隆,它主要是提供了交互式的命令讓我們可以動(dòng)態(tài)的更改模板,然后用一句命令就可以一勞永逸了(當(dāng)然還是要維護(hù)的),這應(yīng)該是最主要的區(qū)別吧,反正現(xiàn)在我是這么想的:cry:。
好了,本章的目的就是帶領(lǐng)大家寫一個(gè)簡(jiǎn)易版的腳手架 xr-cli(名字愛(ài)取啥取啥),目標(biāo)是實(shí)現(xiàn)一個(gè) xr init template-name project-name
這樣的命令,廢話少說(shuō),開始進(jìn)入正題吧:rocket::rocket::rocket:。
源碼地址: https://github.com/lgq627628/xr-cli
前置知識(shí)
其實(shí)一個(gè)簡(jiǎn)易版的 xr-cli 的代碼量并不多,所以這里我們先來(lái)小小介紹一下其中要依賴的包,如果你用過(guò)這些工具可以跳過(guò),沒(méi)用過(guò)的請(qǐng)務(wù)必一定要瞟一眼。
commander
這是用來(lái)編寫指令和處理命令行的,具體用法如下:
const program = require("commander"); // 定義指令 program .version('0.0.1') .command('init', 'Generate a new project from a template') .action(() => { // 回調(diào)函數(shù) }) // 解析命令行參數(shù) program.parse(process.argv);
回憶一下,我們?cè)眠^(guò)的 vue init
的命令就是這樣聲明的。
inquirer
這是個(gè)強(qiáng)大的交互式命令行工具,具體用法如下:
const inquirer = require('inquirer'); inquirer .prompt([ // 一些交互式的問(wèn)題 ]) .then(answers => { // 回調(diào)函數(shù),answers 就是用戶輸入的內(nèi)容,是個(gè)對(duì)象 });
想象一下我們用 vue init webpack project-name
之后是不是會(huì)有幾個(gè)交互問(wèn)題,問(wèn)你文件名啊、作者啊、描述啊、要不要用 eslint 啊等等之類的,就是用這個(gè)來(lái)寫的。
chalk
這是用來(lái)修改控制臺(tái)輸出內(nèi)容樣式的,比如顏色啊,具體用法如下:
const chalk = require('chalk'); console.log(chalk.green('success')); console.log(chalk.red('error'));
ora
這是一個(gè)好看的加載,就是你下載的時(shí)候會(huì)有個(gè)轉(zhuǎn)圈圈的那種效果,用法如下:
const ora = require('ora') let spinner = ora('downloading template ...') spinner.start()
download-git-repo
看名字很明顯了,這是用來(lái)下載遠(yuǎn)程模板的,支持 GitHub、 GitLab 和 Bitbucket 等,用法如下:
const download = require('download-git-repo') download(repository, destination, options, callback)
其中 repository 是遠(yuǎn)程倉(cāng)庫(kù)地址;destination 是存放下載的文件路徑,也可以直接寫文件名,默認(rèn)就是當(dāng)前目錄;options 是一些選項(xiàng),比如 { clone:boolean }
表示用 http download 還是 git clone 的形式下載。
目錄搭建
ok,有了上面的知識(shí)儲(chǔ)備之后,我們就正式開始擼了。
首先我們要?jiǎng)?chuàng)建一個(gè)文件夾,并取名叫 xr-cli;
在該目錄下執(zhí)行 npm init
命令(你應(yīng)該有安裝 node 吧:joy:),一路回車,就會(huì)生成一個(gè)生成 package.json 文件,在 package.json 里面寫入以下依賴并執(zhí)行 npm install
安裝,如下:
"dependencies": { "chalk": "^2.4.2", "commander": "^2.19.0", "download-git-repo": "^1.1.0", "inquirer": "^6.2.2", "ora": "^3.2.0" }
新建一個(gè) bin 文件夾,并在 bin 目錄下新建一個(gè)無(wú)后綴名的 xr 文件,并寫上:
#!/usr/bin/env node console.log('hello');
這個(gè)文件就是我們整個(gè)腳手架的入口文件,我們用 node ./bin/xr
運(yùn)行一下,就能在控制臺(tái)打印出 hello,如下圖:
這里要注意開頭的 #!/usr/bin/env node
這個(gè)語(yǔ)句必須加上,主要是為了讓系統(tǒng)看到這一行的時(shí)候,會(huì)沿著該路徑去查找 node 并執(zhí)行,主要是為了兼容 Mac ,確??蓤?zhí)行。
bin 目錄初始化
當(dāng)前,bin 目錄下就只有一個(gè)文件,就是入口文件 xr。所以現(xiàn)在我們先來(lái)編寫這個(gè)文件,由于內(nèi)容較少,我們直接看代碼:
#!/usr/bin/env node const program = require('commander') // 定義當(dāng)前版本 // 定義使用方法 // 定義四個(gè)指令 program .version(require('../package').version) .usage('[options]') .command('add', 'add a new template') .command('delete', 'delete a template') .command('list', 'list all the templates') .command('init', 'generate a new project from a template') // 解析命令行參數(shù) program.parse(process.argv)
這個(gè)文件的主要作用就是定義指令,現(xiàn)在我們用 node ./bin/xr
運(yùn)行一下,就能看到如下結(jié)果:
當(dāng)然,你可能會(huì)覺(jué)得每次輸入 node ./bin/xr
這個(gè)命令有點(diǎn)麻煩,沒(méi)關(guān)系,我們可以在 package.json 里面寫入已下內(nèi)容:
// bin 用來(lái)指定每個(gè)命令所對(duì)應(yīng)的可執(zhí)行文件的位置 "bin": { "xr": "bin/xr" }
然后在根目錄下執(zhí)行 npm link
(就是把命令掛載到全局的意思),這樣我們每次只要輸入 xr,就可以直接運(yùn)行了,so cool,就像下面這樣:
是不是好像有點(diǎn)樣子了呢:grin::grin::grin:,那就讓我們繼續(xù)完善下 bin 目錄吧!ok,讓我們?cè)?bin 目錄下再新建四個(gè)文件,分別對(duì)應(yīng)上面的四個(gè)指令,然后分別處理四個(gè)指令要做的事情,如下圖:
同樣的,我們修改一下 package.json 里面的 bin 內(nèi)容,如下:
"bin": { "xr": "bin/xr", "xr-add": "bin/xr-add", "xr-delete": "bin/xr-delete", "xr-list": "bin/xr-list", "xr-init": "bin/xr-init" }
然后執(zhí)行 npm unlink
解綁全局命令,再執(zhí)行 npm link
重新把命令綁定到全局,就像下面這樣:
最后順便在根目錄下新建一個(gè) template.json 文件,里面的內(nèi)容就是一個(gè) {}
。
編寫具體指令
好了,一切準(zhǔn)備就緒,接下來(lái)就讓我們來(lái)寫下具體的四個(gè)指令吧。
xr-add
這個(gè)內(nèi)容也是比較少,直接看代碼:
#!/usr/bin/env node // 交互式命令行 const inquirer = require('inquirer') // 修改控制臺(tái)字符串的樣式 const chalk = require('chalk') // node 內(nèi)置文件模塊 const fs = require('fs') // 讀取根目錄下的 template.json const tplObj = require(`${__dirname}/../template`) // 自定義交互式命令行的問(wèn)題及簡(jiǎn)單的校驗(yàn) let question = [ { name: "name", type: 'input', message: "請(qǐng)輸入模板名稱", validate (val) { if (val === '') { return 'Name is required!' } else if (tplObj[val]) { return 'Template has already existed!' } else { return true } } }, { name: "url", type: 'input', message: "請(qǐng)輸入模板地址", validate (val) { if (val === '') return 'The url is required!' return true } } ] inquirer .prompt(question).then(answers => { // answers 就是用戶輸入的內(nèi)容,是個(gè)對(duì)象 let { name, url } = answers; // 過(guò)濾 unicode 字符 tplObj[name] = url.replace(/[\u0000-\u0019]/g, '') // 把模板信息寫入 template.json 文件中 fs.writeFile(`${__dirname}/../template.json`, JSON.stringify(tplObj), 'utf-8', err => { if (err) console.log(err) console.log('\n') console.log(chalk.green('Added successfully!\n')) console.log(chalk.grey('The latest template list is: \n')) console.log(tplObj) console.log('\n') }) })
這個(gè)文件主要目的就是添加模板并存儲(chǔ)起來(lái),上面的注釋應(yīng)該都寫的挺清楚了。我們執(zhí)行 xr add
來(lái)看看效果:
這里的模板名稱(自己隨便取)相當(dāng)于 vue init webpack project-name
當(dāng)中的 webpack
;模板地址要注意一下,像下面這樣寫就可以,這里以 github 為例:
xr-delete
如果你理解了上面的那個(gè)步驟,這步對(duì)你來(lái)說(shuō)應(yīng)該也是灑灑水啦!上代碼:
#!/usr/bin/env node const inquirer = require('inquirer') const chalk = require('chalk') const fs = require('fs') const tplObj = require(`${__dirname}/../template`) let question = [ { name: "name", message: "請(qǐng)輸入要?jiǎng)h除的模板名稱", validate (val) { if (val === '') { return 'Name is required!' } else if (!tplObj[val]) { return 'Template does not exist!' } else { return true } } } ] inquirer .prompt(question).then(answers => { let { name } = answers; delete tplObj[name] // 更新 template.json 文件 fs.writeFile(`${__dirname}/../template.json`, JSON.stringify(tplObj), 'utf-8', err => { if (err) console.log(err) console.log('\n') console.log(chalk.green('Deleted successfully!\n')) console.log(chalk.grey('The latest template list is: \n')) console.log(tplObj) console.log('\n') }) })
應(yīng)該很好理解,就不過(guò)多解釋了,我們直接執(zhí)行 xr delete
看下效果:
xr-list
這個(gè)更簡(jiǎn)單了,兩行代碼搞定:
#!/usr/bin/env node const tplObj = require(`${__dirname}/../template`) console.log(tplObj)
是不是簡(jiǎn)單到爆:boom:。我們執(zhí)行 xr list
看看效果:
因?yàn)閯偛乓惶砑右粍h除,所以目前沒(méi)有模板,就輸出 {}
。
xr-init
這應(yīng)該是最主要(但不難)的一步了,畢竟我們寫到現(xiàn)在還沒(méi)有通過(guò)命令初始化過(guò)一個(gè)項(xiàng)目呢:sob:。所以這步的重點(diǎn)就是執(zhí)行 download
方法,并傳入相應(yīng)參數(shù),具體看代碼:
#!/usr/bin/env node const program = require('commander') const chalk = require('chalk') const ora = require('ora') const download = require('download-git-repo') const tplObj = require(`${__dirname}/../template`) program .usage('[project-name]') program.parse(process.argv) // 當(dāng)沒(méi)有輸入?yún)?shù)的時(shí)候給個(gè)提示 if (program.args.length < 1) return program.help() // 好比 vue init webpack project-name 的命令一樣,第一個(gè)參數(shù)是 webpack,第二個(gè)參數(shù)是 project-name let templateName = program.args[0] let projectName = program.args[1] // 小小校驗(yàn)一下參數(shù) if (!tplObj[templateName]) { console.log(chalk.red('\n Template does not exit! \n ')) return } if (!projectName) { console.log(chalk.red('\n Project should not be empty! \n ')) return } url = tplObj[templateName] console.log(chalk.white('\n Start generating... \n')) // 出現(xiàn)加載圖標(biāo) const spinner = ora("Downloading..."); spinner.start(); // 執(zhí)行下載方法并傳入?yún)?shù) download ( url, projectName, err => { if (err) { spinner.fail(); console.log(chalk.red(`Generation failed. ${err}`)) return } // 結(jié)束加載圖標(biāo) spinner.succeed(); console.log(chalk.green('\n Generation completed!')) console.log('\n To get started') console.log(`\n cd ${projectName} \n`) } )
ok,我們執(zhí)行一下 xr init simple test
,記得先執(zhí)行一下 xr add
:
現(xiàn)在我們就可以在左側(cè)的目錄中看到 test 項(xiàng)目了,如下圖:
至此,一個(gè)小小的腳手架就做完了。:rose::rose::rose:此處應(yīng)該有鮮花和掌聲:clap::clap::clap:
發(fā)布到 npm
既然以上命令都執(zhí)行成功了,那接下來(lái)我們就把它發(fā)布到 npm 上吧(寫都寫了,不能浪費(fèi):grimacing:)。
刪除 test 文件夾,它就本地測(cè)試用的,用完就拋棄它(當(dāng)然做人不能這樣)
在根目錄下新建 README.md 文件,隨便寫點(diǎn)使用說(shuō)明,假裝正經(jīng)一下
在根目錄下新建 .npmignore 文件,并寫入 /node_modules
,意思就是發(fā)布的時(shí)候忽略 node_modules 文件夾,
去 npm 官網(wǎng)注冊(cè)個(gè)賬號(hào)(很簡(jiǎn)單的),同時(shí)搜索一下 xr-cli 這個(gè)名字,看看有沒(méi)有人用,有的話就換一個(gè)羅
現(xiàn)在讓我們回到項(xiàng)目根目錄,執(zhí)行 npm login
登入 npm 賬號(hào),再執(zhí)行 npm publish
發(fā)布,就像下面這樣:
沒(méi)錯(cuò),就是這樣兩個(gè)簡(jiǎn)單的命令,我們就發(fā)布成功啦,真是可喜可賀:beer::beer::beer:。大概過(guò)一分鐘左右(反正挺快的),我們?cè)偃?npm 官網(wǎng)搜下 xr-cli,就可以看到自己的腳手架啦,哈哈哈哈,賊開心:+1::+1::+1:。
這里補(bǔ)充說(shuō)明一點(diǎn):根據(jù)規(guī)范,只有在發(fā)包的24小時(shí)內(nèi)才允許撤銷發(fā)布的包,所以為了不污染 npm 網(wǎng)站,如果只是測(cè)試的話就執(zhí)行 npm unpublish --force
刪除吧,畢竟我們都是有素質(zhì)的人。
小試牛刀
別急,還沒(méi)有結(jié)束:no_good:?♀?。發(fā)都發(fā)出去了,怎么也得驗(yàn)證一波撒。嗯,說(shuō)的有道理,無(wú)法反駁,那就趕緊驗(yàn)收吧!這里我們記得先用 npm unlink
解綁一下命令,不然會(huì)相互影響。下面我們打開終端,輸入 npm i xr-cli -g
全局安裝一下腳手架,然后執(zhí)行 xr
,如果出現(xiàn)下圖中的模樣就說(shuō)明已經(jīng)安裝成功了。
接下來(lái)進(jìn)入到桌面,執(zhí)行 xr init simple xr-test
,不一會(huì)就可以在桌面上看到自己的項(xiàng)目啦。
以上是“仿vue-cli如何搭建屬于自己的腳手架”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!