Vue3 企業級優雅實戰

2022-12-06 18:00:09

前面的文章分享了元件庫的開發、example、元件庫檔案,本文分享元件庫 cli 開發。

1 為什麼要開發元件庫 cli

回顧一個新元件的完整開發步驟:

1 在 packages 目錄下建立元件目錄 xxx:
1.1 使用 pnpm 初始化 package.json,修改 name 屬性;
1.2 在該目錄中建立 src 目錄和 index.ts 檔案;
1.3 在 src 目錄下建立 types.ts 檔案和 index.tsx / index.vue 檔案;

2 在元件庫的入口模組 packages/yyg-demo-ui:
2.1 使用 pnpm install 安裝 1.1 建立的 xxx;
2.2 在 packages/xxx-ui/index.ts 中引入 xxx,並新增到 components 陣列中;

3 packages/scss/components/ 目錄:
3.1 在該目錄下建立 _xxx.module.scss;
3.2 在該目錄中的 index.scss 中引入 _xxx.module.scss;

4 元件庫檔案:
4.1 在 docs/components 目錄下建立 xxx.md 檔案;
4.2 在 docs/demos 目錄下建立 xxx 目錄,並在該目錄中建立 xxx.vue 檔案;
4.3 在 docs/components.ts 中新增元件選單項;

該步驟是一個機械化的流程操作,涉及新建或修改十多個檔案,費事費力,純屬體力活。這種情況下就可以使用工具替代咱們完成這些操作,開發一個 cli,執行命令、輸入元件名就自動建立元件,完成上述操作,如此便可以將注意力集中到元件和業務的開發中。

2 開發 cli 使用到的技術

開發 cli 的庫有很多,優雅哥在這裡使用的還是最傳統的技術棧,在下面使用的這些庫時要注意版本號:

版本 作用
commander ^9.4.1 接收輸入的命令,解析命令引數
chalk 4.1.2 控制檯輸出的文字顏色
inquirer 8.2.5 命令列互動,在命令列提示使用者輸入,獲取到使用者輸入的內容
log-symbols 4.1.0 控制檯輸出的圖示,如 success、failure 等狀態
ora 5.4.1 在控制檯顯示 loading
shelljs ^0.8.5 執行 cmd 命令,如 cd、pnpm install 等

3 搭建 cli 開發框架

有了上面的知識準備,接下來就進入實戰 cli:

3.1 初始化 cli 模組

在命令列中進入 cli 目錄,依舊使用 pnpm 初始化:

pnpm init

修改生成的 package.json 檔案 name 屬性:

{
  "name": "@yyg-demo-ui/cli",
  "version": "1.0.0",
  "description": "命令列工具",
  "author": "程式設計師優雅哥",
  "license": "ISC"
}

cli 目錄下建立 ts 組態檔 tsconfig.json

{
  "compilerOptions": {
    "target": "es2015",
    "lib": [
      "es2015"
    ],
    "module": "commonjs",
    "rootDir": "./",
    "allowJs": true,
    "isolatedModules": false,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true
  }
}

cli 目錄下建立 index.ts 檔案作為入口:

#!/usr/bin/env node

console.log('hello cli!')

該檔案第一行不能省略,這句話的意思是使用 node 來執行這個檔案,並且在 /use/bin/env 環境變數中去找 node 執行器。

3.2 ts-node 執行 ts 檔案

有了入口檔案,怎麼去執行它呢?當前 index.ts 中沒有任何 TypeScript 語法,可以使用 node index.js 來執行,但有 TypeScript 語法時,就需要 tsc 先編譯 ts 檔案,再使用 node 命令來執行。這樣每次執行比較麻煩,慶幸可以使用 ts-node 來執行。

cli 目錄下按照 ts-node 為開發依賴:

pnpm install ts-node -D

可以嘗試在命令列中執行 ts-node index.ts

直接這麼執行不優雅,優雅哥更寧願在 clipackage.json 新增 scripts

"scripts": {
  "gen": "ts-node ./index.ts create"
},

在上面的 gen 命令中,新增了一個引數 create,在後面會解析出這個引數。

重新在命令列執行:

pnpm run gen

控制檯能正常輸出 hello cli!,ts 檔案可以正常執行。

3.3 原始碼目錄

上面建立的 index.ts 是命令執行的入口,現在咱們在 cli 中建立 src 目錄存放原始碼,並在 src 中建立 index.ts 作為原始碼的入口,首先在該檔案中定義一個入口函數:

src/index.ts

export const mainEntry = () => {
  console.log('hello cli mainEntry')
}

在外層的 index.ts 中(cli/index.ts)呼叫該函數:

#!/usr/bin/env node

import { mainEntry } from './src'

mainEntry()

執行 pnpm run gen 測試程式是否正常執行。

3.4 引數解析

前面定義的 gen 命令攜帶了引數 create,要怎麼解析出這個引數呢?可以使用 commander 庫來完成。

cli 中安裝 commander

pnpm install commander -D

修改 cli/src/index.ts 檔案,使用 commander 來解析引數:

import { program } from 'commander'

export const mainEntry = () => {
  console.log('hello cli mainEntry')

  program.version(require('../package').version)
    .usage('<command> [arguments]')

  program.command('create')
    .description('create a new component')
    .alias('c')
    .action(() => {
      console.log('建立元件')
    })

  program.parse(process.argv)

  if (!program.args.length) {
    program.help()
  }
}

如果直接執行 ts-node index.ts,會輸出命令使用幫助:

hello cli mainEntry
Usage: index <command> [arguments]

Options:
  -V, --version   output the version number
  -h, --help      display help for command

Commands:
  create|c        create a new component
  help [command]  display help for command

執行 pnpm run gen (即 ts-node index.ts create),則會進入 create 命令的 action 回撥函數中:

hello cli mainEntry
建立元件

cli/src/ 目錄下建立目錄 command,並在該目錄中建立 create-component.ts 檔案,該檔案用於處理引數為 create 時執行的內容(即建立元件相關的目錄檔案等):

export const createComponent = () => {
  console.log('建立新組建')
}

該檔案匯出了函數 createComponent,該函數的內部實現邏輯咱們在下一篇文章實現,本文先將 cli 架子搭起來。

修改 cli/src/index.ts 檔案,首先引入 createComponent 函數,然後在 create 命令的 action 中呼叫它:

...
import { createComponent } from './command/create-component'

export const mainEntry = () => {
  ...
  program.command('create')
    ...
    action(createComponent)
	...
}

執行 gen 命令時,就會呼叫到 createComponent 函數了。

3.5 使用者互動

createComponent 中,首先要提示元件開發人員輸入元件的名稱、中文名、元件型別(tsx、vue),這時候可以使用 inquirer 來實現。先在 cli 下安裝依賴,為了省事,咱把其他依賴一起安裝了:

pnpm install [email protected] [email protected] @types/[email protected] [email protected] [email protected] shelljs  @types/shelljs -D

接著在 create-component.ts 中定義互動提示和變數名:

import inquirer, { QuestionCollection } from 'inquirer'
// 互動提示
const questions: QuestionCollection = [
  {
    name: 'componentName',
    message: 'Input the component name: ',
    default: ''
  },
  {
    name: 'description',
    message: 'Input the component description: ',
    default: ''
  },
  {
    type: 'list',
    name: 'componentType',
    message: 'Choose the component type: ',
    choices: [
      'tsx', 'vue'
    ]
  }
]

最後在 createComponent 函數中使用 inquirer 實現互動提示資訊:

const createNewComponent = (componentName: string, description: string, componentType: string) => {
  console.log(componentName, description, componentType)
}

export const createComponent = () => {
  inquirer.prompt(questions).then(({ componentName, description, componentType }) => {
    createNewComponent(componentName, description, componentType)
  })
}

執行 pnpm run gen 執行效果如下:

image-20221115141328774

到這裡,元件庫 cli 的架子咱們就搭建起來了,後面只需要實現 createNewComponent 函數即可,在該函數中建立目錄、檔案、執行命令等。

3.6 美化紀錄檔

本文最後咱們玩點優雅的東西。如果直接使用 console.log 輸出,只有黑白色,不優雅,咱可以使用 chalk 改變輸出的文字的顏色,並通過 log-symbols 加些圖示。首先在 src 下建立 util 目錄,在該目錄中建立 log-utils.ts 檔案,用來封裝優雅版的 console.log

import chalk from 'chalk'
import logSymbols from 'log-symbols'

export const r = (msg: string, showIcon = true): void => {
  if (showIcon) {
    console.log(logSymbols.error, chalk.red(msg))
  } else {
    console.log(chalk.red(msg))
  }
}

export const g = (msg: string, showIcon = true): void => {
  if (showIcon) {
    console.log(logSymbols.success, chalk.green(msg))
  } else {
    console.log(chalk.green(msg))
  }
}

export const c = (msg: string): void => {
  console.log(logSymbols.info, chalk.cyan(msg))
}

該檔案匯出了 r、g、c 三個函數,其他檔案使用時非常簡便:

c('yyg-demo-ui cli 工具')

本文搭建好 cli 的架子,下文將完成 createNewComponent 函數,實現元件建立的全過程。

感謝閱讀,公號同名「程式設計師優雅哥」。