從0搭建vue3元件庫: 如何完整搭建一個前端腳手架?

2022-10-25 12:01:19

相信大家在前端開發中都使用過很多前端腳手架,如vue-cli,create-vite,create-vue等;本篇文章將會為大家詳細介紹這些前端腳手架是如何實現的,並且從零實現一個create-kitty腳手架釋出到npm上。

pnpm搭建Monorepo環境

使用pnpm管理對專案進行管理是非常方便的,極大的解決了多個包在本地偵錯繁瑣的問題。

什麼是Monorepo?

就是指在一個大的專案倉庫中,管理多個模組/包(package),這種型別的專案大都在專案根目錄下有一個packages資料夾,分多個專案管理。大概結構如下:

-- packages
  -- pkg1
    --package.json
  -- pkg2
    --package.json
--package.json
  

簡單來說就是單倉庫 多專案

目前很多我們熟知的專案都是採用這種模式,如Vant,ElementUI,Vue3等。打造一個Monorepo環境的工具有很多,如:lerna、pnpm、yarn等,這裡我們將使用pnpm來開發我們的UI元件庫。

使用pnpm

安裝

首先新建資料夾kitty-ui;然後執行

npm install pnpm -g

初始化package.json

pnpm init

新建組態檔 .npmrc

shamefully-hoist = true

這裡簡單說下為什麼要設定shamefully-hoist

如果某些工具僅在根目錄的node_modules時才有效,可以將其設定為true來提升那些不在根目錄的node_modules,就是將你安裝的依賴包的依賴包的依賴包的...都放到同一級別(扁平化)。說白了就是不設定為true有些包就有可能會出問題。

monorepo的實現

接下就是pnpm如何實現monorepo的了。

為了我們各個專案之間能夠互相參照我們要在根目錄下新建一個pnpm-workspace.yaml檔案將我們的包關聯起來

packages:
    - 'packages/**'

這樣就能將我們專案下的packages目錄下的所有包關聯起來了,當然如果你想關聯更多目錄你只需要往裡面新增即可。根據上面的目錄結構很顯然你在根目錄下新packages資料夾,packages資料夾新建create-kitty以及測試用的cli-demo資料夾,並分別執行pnpm init

腳手架簡單實現

create-kittypackage.json中新增bin屬性然後指向index.js。這裡去掉了main屬性,因為我們開發的不是工具包。

{
  "name": "create-kitty",
  "version": "1.0.0",
  "description": "",
  "bin": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

當然,bin也支援物件格式,讓腳手架可以使用多個命令

"bin": {
    "create-kitty": "index.js",
    "create-app": "index.js"
  },

新建create-kitty/index.js作為腳手架入口

#! /usr/bin/env node

console.log("hello kitty")

注意cli入口檔案需要加#! /usr/bin/env node指定指令碼的解釋程式為node,否則會報錯

本地測試腳手架

來到測試包cli-demo資料夾下直安裝create-kitty

pnpm add create-kitty

然後就會發現cli-demo下的package出現依賴,同時加上scripts

{
  "name": "cli-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "create-kitty": "create-kitty"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "create-kitty": "workspace:^1.0.0"
  }
}

然後執行pnpm run create-kitty

說明

當我們上線的時候可以直接執行npm create kitty或者npm init kitty,它們其實就是執行npx create-kitty

解析使用者輸入引數

一般腳手架都會根據使用者輸入不同命令來做出不同操作,比如使用者輸入kitty-ui -v提示版本號,kitty-ui -h顯示幫助資訊等。而實現這些基本原理就是process.argv

create-kitty下的入口檔案index.js修改為

#! /usr/bin/env node

console.log(process.argv);

然後執行這個檔案並帶幾個引數

然後會發現使用者傳的引數在process.argv陣列的第二位以後,這樣我們就可以根據使用者輸入不同引數做不同操作了。但是這樣很不方便,所以我們可以使用框架來解決。

使用第三方庫解析引數

首先安裝command-line-args

pnpm add command-line-args -S

接下來看它是如何獲取使用者輸入引數的

#! /usr/bin/env node
import commandLineArgs from 'command-line-args';

//設定命令引數
const optionDefinitions = [
  { name: 'version', alias: 'v', type: Boolean },
  { name: 'arg1', type: String },
  { name: 'arg2', type: Number },
];
const options = commandLineArgs(optionDefinitions);
console.log(options);

注意這裡使用了es6的語法,所以需要將package.json中的type指定為module

接下來實戰一些,檢測使用者輸入--help指令,然後我們輸出一個幫助的設定。

首先安裝command-line-usage

pnpm add command-line-usage -S

首先引入commandLineUsage,然後寫個設定

import commandLineUsage from 'command-line-usage';
//幫助內容
const helpSections = [
  {
    header: 'create-kitty',
    content: '一個快速生成元件庫搭建環境的腳手架',
  },
  {
    header: 'Options',
    optionList: [
      {
        name: 'version',
        typeLabel: '{underline boolean}',
        description: '版本號',
      },
      {
        name: 'arg1',
        typeLabel: '{underline string}',
        description: '引數1',
      },
      {
        name: 'arg2',
        typeLabel: '{underline number}',
        description: '引數2',
      },
    ],
  },
];

command-line-args中設定個help命令,當獲取到help的時候直接列印

const optionDefinitions = [
  { name: 'help', alias: 'h', type: Boolean },
  { name: 'version', alias: 'v', type: Boolean },
  { name: 'arg1', type: String },
  { name: 'arg2', type: Number },
];
const options = commandLineArgs(optionDefinitions);
if (options.help) console.log(commandLineUsage(helpSections))

但是這樣好像不太好看