vite不能選配方案?vite-creater強勢來襲!

加伊bky發表於2023-04-28

我正在參加「掘金·啟航計劃」

專案背景

vite出現之後,迅速帶走了一大波webpack的使用者,即使是對打包工具不熟悉的小白,也能很快感受到兩者的區別——vite快的多!

vite官方文件第一句也是講述其名字的由來 Vite (法語意為 "快速的") ,其logo也與其名字一樣,處處都透露著一個字,那就是快!

但是習慣了vue-cli的同學(我),對於一個不能儲存模板策略的工具,是無法忍受的,它居然每次都需要我選擇模板、選擇用js還是ts,這是讓人無法忍受的。當然,vite官方還提供了社群維護的模板 即 image-20230428111113806 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內建了一個貼心的選配策略:

image-20230428112459247

這也是目前應用最多的,開發起來最容易的一套策略,在此直接回車,你會直接一鍵生成專案

image-20230428112853574

如果你不喜歡,或者你需要更多的東西,可以點選 "點選進入自定義流程"

自定義選配

vite-creater會問詢一系列常用套件,包括:css前處理器、使用js還是ts、是否使用vue-router、使用vuex還是pinia

(vite-creater目前版本只支援 問詢vue常用包,如需其他框架,可以全選擇no,然後在自定義第三方包中新增你的框架需要的包即可)

最後,vite-creater會問你,是否需要其他的第三方包,比如我們需要使用 超好用的大屏自適應工具 vue-autofit ,我們就輸入vue-autofit

image-20230428113321682

最後,可以選擇將此選配方案儲存,你可以選擇給它取一個名字,當然也可以不取,因為vite-creater會在預設方案列表中展示所有依賴名稱和使用的語言。

如果vite-creater要求你選擇框架,你可以根據自己的需要選擇你的框架:image-20230428113518967

當選擇完框架後,即可快速完成專案建立了!並且已經下載了你的自定義包。

image-20230428113553834

image-20230428115522189

使用儲存的選配方案

image-20230428115850797

當你建立過一個方案並選擇了儲存後,工具會在下次使用時向你展示你儲存的選配方案,直接選擇即可一鍵生成專案,不用再重複選配過程。

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命令即可釋出。

檢視 vite-creater 的 npm主頁

本專案已在 github開源 github原始碼 ? 點選走你

結語

懦弱之舉,我決不姑息!

相關文章