使用Vue.js編寫命令列介面,前端開發CLI的利器

語言: CN / TW / HK

前言

大家好,我是webfansplz.繼 將 Vue 渲染到嵌入式液晶屏 後,今天要跟大家分享的是如何將Vue渲染到命令列工具 :).關於命令列工具,大家應該都比較熟悉了,比如vue-cli、Vite等.我們在編寫前端應用面向使用者時,通常會非常關注使用者體驗,作為開發者,我們在使用工具時,它給予我們的開發者體驗(DX)我們也會十分關注. 現代前端工程化離不開CLI的開發與使用、那麼是否能有較低成本的方案能讓前端小夥伴快速開發CLI,大家可以像編寫前端應用一樣搞定它.因此,Temir應運而生.

Temir

介紹

Temir,一個用Vue元件來編寫命令列介面應用的工具.開發者只需要使用Vue就可以編寫命令列應用,不需要任何額外的學習成本.

<script lang="ts" setup>
import { ref } from '@vue/runtime-core'
import { TBox, TText } from '@temir/core'
const counter = ref(0)
setInterval(() => {
  counter.value++
}, 100)
</script>

<template>
  <TBox>
    <TText color="green">
      {{ counter }} tests passed
    </TText>
  </TBox>
</template>

元件

Temir提供了一些基礎元件幫助開發者編寫與擴充套件命令列工具:

文字元件 (Text)

文字元件可以顯示文字,將其樣式更改為粗體、下劃線、斜體或刪除線.

<TText color="green">
  I am green
</TText>

<TText color="black" background-color="white">
  I am black on white
</TText>

<TText color="white">
  I am white
</TText>

<TText :bold="true">
  I am bold
</TText>

<TText :italic="true">
  I am italic
</TText>

<TText :underline="true">
  I am underline
</TText>

<TText :strikethrough="true">
  I am strikethrough
</TText>

<TText :inverse="true">
  I am inversed
</TText>

盒子元件 (Box)

<Box> 是構建佈局必不可少的Temir元件.就像在瀏覽器中 <div style='display: flex'>. 它提供了一些構建佈局的常用屬性,比如尺寸、內外邊距、對齊方式等.

<template>
  <TBox justify-content="flex-start">
    <TText>X</TText>
  </TBox>
  // [X      ]

  <TBox justify-content="center">
    <TText>X</TText>
  </TBox>
  // [   X   ]

  <TBox justify-content="flex-end">
    <TText>X</TText>
  </TBox>
  // [      X]

  <TBox justify-content="space-between">
    <TText>X</TText>
    <TText>Y</TText>
  </TBox>
  // [X      Y]

  <TBox justify-content="space-around">
    <TText>X</TText>
    <TText>Y</TText>
  </TBox>
  // [  X   Y  ]
</template>

換行元件 (Newline)

新增一個或多個換行符(\n)。 必須在 <Text> 元件中使用。

<script>
import { TBox, TNewline, TText } from '@temir/core'
</script>

<template>
  <TBox>
    <TText>
      <TText color="green">
        Hello
      </TText>
      <TNewline />
      <TText color="red">
        World
      </TText>
    </TText>
  </TBox>
</template>

填充元件 (Spacer)

沿其包含佈局的主軸展開的靈活空間。 作為填充元素之間所有可用空間的快捷方式,它非常有用。

例如,在具有預設伸縮方向( row )的 <Box> 中使用 <Spacer> 將把"Left"定位到左邊,並將"Right"推到右邊。

<script lang="ts" setup>
import { TBox, TSpacer, TText } from '@temir/core'
</script>

<template>
  <TBox>
    <TText>Left</TText>
    <TSpacer />
    <TText>Right</TText>
  </TBox>
</template>

超連結元件 (Link)

<script lang="ts" setup>
import { TBox, TText } from '@temir/core'
import TLink from '@temir/link'
</script>

<template>
  <TBox
    :margin="5"
    width="20"
    border-style="round"
    justify-content="center"
  >
    <TLink url="http://github.com">
      <TText color="yellow">
        Hi
      </TText>
      <TText color="cyan">
        Github
      </TText>
    </TLink>
  </TBox>
</template>

載入中元件 (Spinner)

<script lang="ts" setup>
import { TBox, TText } from '@temir/core'
import TSpinner from '@temir/spinner'
</script>

<template>
  <TBox
    :margin="5"
    width="20"
    border-style="round"
    justify-content="center"
  >
    <TText>
      <TText color="yellow">
        <TSpinner />
      </TText>
      Loading
    </TText>
  </TBox>
</template>

標籤頁元件 (Tab)

<script lang="ts" setup>
import { computed, ref } from '@vue/runtime-core'
import { TBox, TText } from '@temir/core'
import { TTab, TTabs } from '@temir/tab'

const tabs = ['Vue', 'React', 'Angular', 'Solid', 'Svelte']
const activeIndex = ref(0)
const selectedText = computed(() => tabs[activeIndex.value])
</script>

<template>
  <TBox>
    <TText>
      Selected Text :
      <TText color="red">
        {{ selectedText }}
      </TText>
    </TText>
  </TBox>

  <TBox>
    <TTabs :on-change="(index) => activeIndex = +index">
      <TTab v-for="item in tabs" :key="item">
        {{ item }}
      </TTab>
    </TTabs>
  </TBox>
</template>

選擇元件

<script lang="ts" setup>
import TSelectInput from '@temir/select-input'

const items = [
  {
    label: 'Vue',
    value: 'Vue',
  },
  {
    label: 'Vite',
    value: 'Vite',
  },
  {
    label: 'Temir',
    value: 'Temir',
  },
]
function onSelect(value) {
  console.log('selected', value)
}
</script>

<template>
  <TSelectInput :items="items" :on-select="onSelect" />
</template>

安裝

npm install @temir/core

使用

<script lang="ts" setup>
import { ref } from '@vue/runtime-core'
import { TBox, TText } from '@temir/core'
const counter = ref(0)
setInterval(() => {
  counter.value++
}, 100)
</script>

<template>
  <TBox>
    <TText color="green">
      {{ counter }} tests passed
    </TText>
  </TBox>
</template>

HMR支援

前面我們提到了開發者體驗(DX),在現在的前端工程中,對開發者很有幫助且提效的就是HMR,這麼香的東西Temir沒有理由不擁有它,話不多說,直接展示:

開箱即用

使用Temir定製化CLI非常簡單,我們提供了@temir/cli幫助你快速構建一個基於Temir的CLI.

mkdir my-temir-cli

cd my-temir-cli

touch main.ts

npm install @temir/cl

# Dev (開發)

temir main.ts

# Build (打包)

temir build main.ts

你可以通過下載這個例子 來快速開始,你也可以開啟repl.it sandbox來線上體驗和嘗試它。

演示

Hi Temir

Borders

Table

Vitest

實現

  • createRenderer

Temir的實現主要得益於Vue3出色的跨平臺能力,我們可以通過createRenderer API建立一個自定義渲染器,通過建立宿主環境中對應的Node和Element,並對元素進行增刪改查操作.

  • Yoga

Vue提供了跑在命令列介面的介面,那我們就還缺少一個佈局引擎就能把Vue

跑在命令列工具了.Temir使用了Yoga,一款Flexbox佈局引擎.使用你在構建瀏覽器應用時使用過的類似CSS的屬性,為你的CLI構建出色的使用者介面。

致謝

  • 這個專案的靈感來源於ink
  • vite-node為實現HMR提供了強力的支援

結語

文章到這裡就結束了,如果我的文章和專案對你有所啟發和幫助,請給一個star支援作者 ✌