使用 typescript 快速開發一個 cli

cli 的全稱 command-line interface(命令行界面),也就是前端同學常用的腳手架,比如 yovue clireact cli 等。

cli 可以方便我們快速創建項目,下圖是引用 vue cli 的介紹:
vue cli guide

創建項目

運行下面的命令,創建一個項目:

npm init

執行命令完成後,可以看到項目根目錄只有一個 package.json 文件。

demo1

在 package.json 文件增加 bin 對象,並指定入口文件 dist/index.js。

在命令行運行需要在入口文件的第一行增加 #!/usr/bin/env node,告訴系統用 node 運行這個文件。

{
  "name": "cli-demo",
  "version": "0.0.1",
  "description": "cli demo",
  "keywords": [
    "cli"
  ],
  "bin": {
    "cli-demo": "dist/index.js"
  }
 ...
}

安裝依賴

命令行工具,也會涉及到用戶交互的動作,那麼 node.js 是怎麼實現呢?早有大佬提供了非常好的庫,我們只要拿過來用,主要有兩個庫:

  • commander:完整的 node.js 命令行解決方案。
  • inquirer:交互式命令行工具。

將這兩個庫安裝到項目里:

yarn add commander inquirer

由於是用 typescript 開發,再通過 rollup 打包,先安裝相關的依賴庫:

yarn add typescript rollup rollup-plugin-terser rollup-plugin-typescript2 @types/inquirer -D

配置

由於是用 typescript 開發,首先需要配置一下 tsconfig.json。

{
  "compilerOptions": {
    "target": "ES6",
    "module": "ESNext",
    "sourceMap": false,
    "declaration": false,
    "outDir": "./dist",
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "resolveJsonModule": true,
    "removeComments": false,
    "importHelpers": true,
    "strict": true,
    "lib": ["ES6", "DOM"]
  },
  "include": ["src"]
}

接下來在根目錄增加一個 rollup.config.js,把 typescript 代碼編譯成 javascript 代碼。前面提到的要在第一行增加 #!/usr/bin/env node 來告訴系統用 node 運行,那麼可以在 rollup.config.js 的 banner 選項,把 #!/usr/bin/env node 寫在最前面。

import typescript from 'typescript'
import json from '@rollup/plugin-json'
import { terser } from 'rollup-plugin-terser'
import typescript2 from 'rollup-plugin-typescript2'

import { dependencies } from './package.json'

const external = Object.keys(dependencies || '')
const globals = external.reduce((prev, current) => {
  const newPrev = prev

  newPrev[current] = current
  return newPrev
}, {})

const defaultConfig = {
  input: './src/index.ts',
  output: {
    file: './dist/index.js',
    format: 'cjs',
    banner: '#!/usr/bin/env node',
    globals
  },
  external,
  plugins: [
    typescript2({
      exclude: 'node_modules/**',
      useTsconfigDeclarationDir: true,
      typescript,
      tsconfig: './tsconfig.json'
    }),
    json(),
    terser()
  ]
}

export default defaultConfig

實現一個簡單的 cli

在根目錄創建一個 src 文件夾,然後再創建一個 index.ts

添加引用

添加引用並實例化 Command 對象。

import { Command } from 'commander'
import pkg from '../package.json'

const program = new Command(pkg.name)

自定義命令

實現一個可交互的自定義命令,模擬在終端(命令行)的登錄功能。使用 command 方法創建一個命令,description 可以用來描述這個命令的作用,登錄處理邏輯則寫在 action 方法里。最後使用 parse(process.argv) 方法,解析命令。更多詳細介紹和使用,可移步://github.com/tj/commander.js/blob/master/Readme_zh-CN.md

program
    .command('login')
    .description('模擬登錄。')
    .action(() => {
       handleLogin()
    })

program.parse(process.argv)

交互的話,用到前面說的 inquirer 庫,接收輸入的用戶名和密碼。選項的 type 的值有 inputpasswordnumbercheckboxeditorlistrawListexpandconfirm,選項 nameinquirer.prompt 方法返回的對象,選項 validate 可用來驗證輸入是否符合規則。更多詳細介紹和使用,可移步://github.com/SBoudrias/Inquirer.js/blob/master/README.md

如果選項 typepassword,可通過 mask 設置掩碼。

const handleLogin = () => {
  // 配置交互的用戶名和密碼
 const prompt = [
    {
      type: 'input',
      name: 'userName',
      message: '用戶名:',
      validate: (value: string) => value.length > 0 || '用戶名不能為空'
    },
    {
      type: 'password',
      name: 'password',
      message: '密碼:',
      mask: '🙈 ',
      validate: (value: string) => value.length > 0 || '密碼不能為空'
    }
  ]

  inquirer.prompt(prompt).then(({ userName, password }) => {
    if (userName === 'demo' || password === '123456') {
      console.log('登錄成功')
      return
    }
    console.log('用戶名或密碼錯誤')
  })
}

其他

一個 cli 工具,幫助信息也是必須的,可以通過 on('--help') 修改自定義幫助信息。

必須在 parse 方法之前。

program.on('--help', () => {
   console.log('\n運行 cli-demo -h | --help 查看命令使用。\n')
})

然後再來修改一下,沒有輸入任何參數的時候,會出現錯誤,可以使用 exitOverride 方法重新退出,在終端(命令行)輸出幫助信息。

program.exitOverride()

try {
  program.parse(process.argv)
} catch (error) {
  program.outputHelp()
}

到這裡,一個簡單的 cli 工具完成了,先本地來測試下看看。在終端(命令行)輸入 npm link,生成一個全局軟連接,可以方便調試和測試。

show demo

轉載請標註來源: //www.cnblogs.com/JasonLong/p/14075724.html