我正在參加「掘金·啟航計劃」
專案背景
vite出現之後,迅速帶走了一大波webpack的使用者,即使是對打包工具不熟悉的小白,也能很快感受到兩者的區別——vite快的多!
vite官方文件第一句也是講述其名字的由來 Vite (法語意為 "快速的") ,其logo也與其名字一樣,處處都透露著一個字,那就是快!
但是習慣了vue-cli的同學(我),對於一個不能儲存模板策略的工具,是無法忍受的,它居然每次都需要我選擇模板、選擇用js還是ts,這是讓人無法忍受的。當然,vite官方還提供了社群維護的模板 即 awesome-vite ,同學可點選連結感受一下這些模板,不能說我們小白用不到吧,可以說是完全不認識。
為此,"好東西" vite-creater 誕生了 github原始碼 ? 點選走你
什麼是vite-creater?
vite-creater是vite的一個前置的自動化cli程式,它可以按照使用者自定義的流程全自動的建立專案,並安裝依賴,當vite-creater提示完成時,你就可以直接npm run了!它呼叫的是npm create vite,除了選擇框架外,其餘的一切操作都不需要你動手,你只需預設一個策略即可!
我需要vite-creater嗎?
如果你是一個熟練的vue玩家,我猜你可能需要它,它可以像vue-cli一樣,儲存一個自己的選配策略,它甚至支援你包含自定義的第三方庫。
如果你還不瞭解vite,或者你希望使用vite原汁原味的功能,你可能不需要vite-creater,不過歡迎你使用,vite-creater會隨著vite的更新而更新!
使用vite-creater
安裝vite-creater
npm i vite-creater -g
快速開始
vcreater init <yourProjectName>
vite-creater內建了一個貼心的選配策略:
這也是目前應用最多的,開發起來最容易的一套策略,在此直接回車,你會直接一鍵生成專案
如果你不喜歡,或者你需要更多的東西,可以點選 "點選進入自定義流程"
自定義選配
vite-creater會問詢一系列常用套件,包括:css前處理器、使用js還是ts、是否使用vue-router、使用vuex還是pinia
(vite-creater目前版本只支援 問詢vue常用包,如需其他框架,可以全選擇no,然後在自定義第三方包中新增你的框架需要的包即可)
最後,vite-creater會問你,是否需要其他的第三方包,比如我們需要使用 超好用的大屏自適應工具 vue-autofit ,我們就輸入vue-autofit
最後,可以選擇將此選配方案儲存,你可以選擇給它取一個名字,當然也可以不取,因為vite-creater會在預設方案列表中展示所有依賴名稱和使用的語言。
如果vite-creater要求你選擇框架,你可以根據自己的需要選擇你的框架:
當選擇完框架後,即可快速完成專案建立了!並且已經下載了你的自定義包。
使用儲存的選配方案
當你建立過一個方案並選擇了儲存後,工具會在下次使用時向你展示你儲存的選配方案,直接選擇即可一鍵生成專案,不用再重複選配過程。
vite-creater是怎麼實現的?
vite-creater是node編寫的。
呼叫Node編寫的cli程式,必須在node環境下才可以執行,因為node的cli實際上是由node代理執行的,即V8引擎去解析和執行的,當我們全域性安裝了一個node cli程式時,node會自動把其命令載入到環境變數中,當我們的JS程式碼被執行時,是node在與作業系統互動。所以,我們不需要了解它具體的執行原理,我們只需要知道JS怎麼寫就可以了。
開發所需的庫
"commander": "^10.0.1" 可以執行dos命令
"inquirer": "^9.2.0" 互動式輸出工具,提供問詢式命令列互動會用到
"configstore": "^6.0.0" 本地儲存,相當於是cookie或者localStorage,用來儲存使用者儲存的選配
開發步驟
使用npm 初始化專案
npm init
需要輸入專案基本資訊,此步驟會初始化一個標準的Npm包,並生成一個package.json ,
注意如果希望釋出到npm,應該先在npm官網檢視是否有相同或相似的包名,有的話是釋出不了的,需要取一個標新立異的包名,或者就需要帶上@userName/的字首
使用commander庫初始化命令
import { program } from 'commander';
program
.version('1.0.0')
.description(`vite-creater是一款用於快速建立vite專案的腳手架工具`);
program
.command('init <projectName>')
.description('使用vite-creater建立專案')
.option('-p, --projectName <string>', 'project name')
.action(async (initProjectName) => {
await askForOptions(initProjectName) //這裡呼叫我們的自定義問詢函式
});
program.parse(process.argv);
在node開發的cli中,可以使用async/await來阻塞程式,以等待步驟完成或者使用者輸入。
使用inquirer建立互動式問詢輸出
import inquirer from 'inquirer';
let preSetRules = [
{
name: 'selectRule',
type: 'list',
message: '選擇一個預設規則,或者進入自定義流程',
choices: preSetRulesList, //這是一個陣列,僅可包含字串,如["item1","item2"]
}
]
let isPreSetRules = await inquirer.prompt(preSetRules)
當如上程式碼被執行時,將會輸出一個可以透過上下箭頭鍵選擇的列表(list)
使用configstore 儲存使用者的選配方案
import Configstore from 'configstore';
const conf = new Configstore('vite-creater');
conf.set("customRulesList", customRulesList); //新建或修改 引數:鍵名,資料
let customRulesList = conf.get('customRulesList');
其中customRulesList 可以是陣列或者物件,當然也可以是字串等,你可以把configstore 完全當作cookie來使用。
使用child_process建立子程式
這是一個node內建的庫,允許開發者建立一個子程式,並與子程式通訊
import { exec } from 'child_process';
function execCreateTs(command) {
console.log('exec:', command);
return new Promise((resolve, reject) => {
const child = exec(command, (err, stdout, stderr) => {
if (err) {
console.log('err::: ', err);
reject(err)
}
})
child.stdout.on('data', async data => { //監聽子程式的輸出
if (data.includes('Package name')) {
process.stdout.write('\x1b[32m' + data + '\x1b[0m');
child.stdin.write('\n');
}
if (data.includes('Vue')) {
process.stdout.write('\x1b[2J\x1b[0f');
process.stdout.write('\x1b[32m' + data + '\x1b[0m');
clearAnimation()
selectFramework(child)
}
if (data.includes('TypeScript')) {
process.stdout.write('\x1b[32m' + data + '\x1b[0m');
process.stdout.write('\x1b[2J\x1b[0f');
child.stdin.write('\n');
resolve(child.stdout)
}
if (data.includes('is not empty')) {
// 退出程式
console.log('\n\x1b[31m×\x1b[0m 目錄已存在');
process.exit();
}
})
})
}
上述程式碼由vite-creater建立ts專案為例,引數command即可以是任何dos命令。下面的if來查詢子程式的輸出中包含的字元,以此來確定子程式進行到哪一步了(我不知道這麼做是不是符合規範的,不過開發的時候我想到了這個辦法。)
細心的同學注意到了selectFramework()方法,這個方法是在子程式中出現了Vue字元時,我們判定vite進入了框架選擇步驟,於是我們將子程式的輸出展示到主程式中,也就是上面提到的框架選擇頁面
selectFramework方法程式碼如下:
async function waitUserPresskey() {
// 返回一個promise物件
return await new Promise((resolve, reject) => {
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', (key) => {
key = key.toString('ascii'); //需要轉為ascii碼
resolve(key)
});
});
}
async function selectFramework(child) {
let input = await waitUserPresskey();
// 如果按下ctrl+c,退出程式
if (input === '\u0003') {
process.exit();
}
child.stdin.write(input); // 向子程式轉發命令
}
當呼叫它時,程式會等待一個使用者輸入,然後直接轉發到子程式中,當子程式再次輸出其他資訊時,又會回到我們上面的監聽,於是,只要使用者還沒有選定框架,vite會一直處在框架選擇頁面,也就是還包含Vue字元,所以會再次進入selectFramework函式,這樣就完成了一個遞迴問詢,直到使用者選擇了框架。
全自動化流程實現
當完成上述步驟之後,我們已經可以看到vite+vue的專案已經建立完成了,這時就已經完成了vite官方工具所做的,一般來說,我們需要進入該資料夾,然後執行npm i ,然後安裝我們需要的包 npm i ....
根據上面的學習,我們理所當然的可以將這一步收納進自動化的範疇,只需執行兩條簡單的dos命令即可。
await execNpmInstall('npm i')
await execNpmInstall(installCommand)
function execNpmInstall(command) {
console.log('exec:', command);
return new Promise((resolve, reject) => {
const child = exec(command, (err, stdout, stderr) => {
if (err) {
reject(err)
}
})
child.stdout.on('data', async data => {
// 當npm i 完成時
if (data.includes('packages in')) {
console.log('\n', data);
resolve(child.stdout)
}
})
})
}
如果我們需要安裝 之前使用者儲存的第三方庫,只需要使用使用conf.get('xxx');去獲取資料,然後傳入該函式即可。
完成
上面簡述了vite-creater的開發過程,至此,我們就可以整理所有的功能,打包釋出了,在本地登入自己的npm賬號後,使用npm publish命令即可釋出。
本專案已在 github開源 github原始碼 ? 點選走你
結語
懦弱之舉,我決不姑息!