如何开发一个cli

Favori,

Cli

图:Philipp Kühn

我们来开发一个下载仓库代码,并通过命令行界面来启动项目的功能

准备工作

安装以下工具,注意版本

clear: 清屏
chalk: 装饰作用,使之终端上的输出加上颜色
figlet: 将字母转化为字符拼成的文字
git-pull-or-clone:将代码下载
inquirer: 在命令行中打出交互式的命令
ora: 优雅的显示loading效果

编码

const { resolve } = require("path");
const fs = require("fs");
const { promisify } = require("util");
const chalk = require("chalk");
const inquirer = require("inquirer");
const figlet = require("figlet");
const clear = require("clear");
const ora = require("ora");
const download = promisify(require("git-pull-or-clone"));
const { spawn, log } = require("./utils");
 
//仓库地址
const repo = "git@github.com:yuanguandong/react-keyevent.git";
 
//清屏
clear();
//打印logo
log(
  figlet.textSync("WIDGET", {
    horizontalLayout: "fitted",
    verticalLayout: "default",
    width: 80,
    whitespaceBreak: true,
  }),
  "green"
);
 
//主流程
const main = async () => {
  // 项⽬名称
  const answer = await inquirer.prompt([
    {
      type: "input",
      message: "DirName:",
      name: "name",
      default: "widgets", // 默认值
    },
  ]);
  const dir = resolve(`./${answer.name}`);
  const process = ora(chalk["gray"](`${dir} loading.....`));
  process.start();
  try {
    await download(repo, dir);
    process.succeed();
    log(`✅ Download Success`);
  } catch (e) {
    log(e, "red");
    process.fail();
  }
  tool(answer.name, dir);
};
 
//工具方法
const actions = {
  install: async ({ dir, name }) => {
    log("installing....", "gray");
    await spawn("pnpm", ["install"], { cwd: `${name}/` });
    log("✅ Installed");
  },
  run: async ({ dir, name }) => {
    const isFile = fs.existsSync(`${dir}/node_modules`);
    if (isFile) {
      const res = await spawn("pnpm", ["run", "test"], { cwd: `${name}/` });
      return;
    } else {
      log("Not Installed", "red");
    }
  },
  exit: async ({ dir, name }) => {
    const isFile = fs.existsSync(`${dir}/node_modules`);
    if (isFile) {
      log("🖐  Bye Bye!", "yellow");
    }
    return;
  },
};
 
//工具箱
async function tool(name, dir) {
  const answer = await inquirer.prompt([
    {
      type: "rawlist",
      message: "Action",
      name: "operation",
      choices: Object.keys(actions),
    },
  ]);
  const res = await actions[answer.operation]({ dir, name });
  if (!res) {
    return;
  }
  tool(name, dir);
}
 
main();
 
module.exports = { main, tool };
 

Utils

const chalk = require("chalk");
const { spawn: _spawn } = require("child_process");
 
const spawn = async (...args) => {
  return new Promise((resolve) => {
    const proc = _spawn(...args);
    proc.stdout.pipe(process.stdout);
    proc.stderr.pipe(process.stderr);
    proc.on("close", (...restArgs) => {
      resolve(restArgs);
    });
  });
};
 
const log = (msg, color = "green", ...arg) =>
  console.log(chalk[color](msg, arg));
 
module.exports = { spawn, log };