美文网首页
Node.js 开发 cli 工具

Node.js 开发 cli 工具

作者: zdxhxh | 来源:发表于2020-12-25 13:41 被阅读0次

    Node.js 开发 cli 工具

    一、为什么需要 cli 工具

    我们见识过了很多的cli工具,例如 vue-cli、create-react-app、angular/cli等。它让开发者摆脱了wepack复杂繁琐的配置,快速、个性化地搭建项目,从而更好地专注业务层面的开发。

    二、起步

    cli的开发思路是复制拷贝,其实与拷贝git仓库无异。

    创建一个文件夹,运行

    npm init -y
    cnpm i arg chalk esm inquirer listr lodash ncp pkg-install --save
    

    上面是我们所需要的依赖,以下是各个安装包的说明

    arg : 解析cli 命令行的参数

    chalk : 让控制台打印颜色

    esm : 这个包可以通过装饰 require,从而可以在模块中使用最新的ECMAScript语法

    inquirer : 控制台交互式命令集合

    lodash : JavaScript 实用工具库

    ncp : 拷贝文件使用库

    pkg-install : 用于在生成的项目中安装依赖

    编辑 package.json

    {
      "name": "zdxhxh-cli",
      "version": "0.0.1",
      "description": "cli 工具",
      "main": "src/main.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "license": "ISC",
      "bin": {
        "xh-cli": "bin/create-project.js"
      },
      "author": {
        "name": "xh"
      },
      "keywords": [
        "cli",
        "create-project"
      ],
      "files": [
        "bin/",
        "src/",
        "templates/"
      ]
    }
    

    说明 :

    • bin : 用来指定内部命令对应可执行文件的位置,当全局安装时这个包时,由于node_modules/.bin/目录会在运行时,加入系统的PATH环境变量,所以在命令行行中直接通过命令来调用这些脚本
    • files : 用来指定那些目录会在发布时,上传到NPM服务器上。这里我们需要bin、src、template这几个目录

    按照以下目录创建文件

    ├─bin
       └─ create-project.js
    ├─src
    |  └─cli.js
    |  └─main.js
    │  └─utils
    |      └─parseArgumentsIntoOptions.js
    |      └─promptForMissingOptions.js
    └─templates
    

    三、编码

    bin/create-project.js中 ,当我们运行 xh-cli时,就会执行该文件

    #!/usr/bin/env node
    // 这样包装后,引入的模块文件可以使用最新的 ES语法
    require = require("esm")(module /*, options*/);
    // 属性会返回一个数组,其中包含当 Node.js 进程被启动时传入的命令行参数
    require("../src/cli").cli(process.argv);
    

    接下来的目标是 : 解析命令行参数。

    src/utils/parseArgumentsIntoOptions.js导出方法,代码如下

    import arg from "arg";
    import get from "lodash/get";
    // 解析命令行参数 rawArgs即 process.argv
    export default function (rawArgs) {
      const args = arg(
        {
          "--git": Boolean,
          "--yes": Boolean,
          "--install": Boolean,
          "--version": Boolean,
          "-y": "--yes",
          "-i": "--install",
          "-v": "--version",
        },
        {
          // process.argv除了前两个,其余的元素才是额外的命令行参数
          argv: rawArgs.slice(2), 
        }
      );
      return {
        skipPrompts: get(args, "--yes", false), // 快速跳过配置 
        version : get(args, "--version", false),
        template: args._[0],
        runInstall: get(args, "--install", false),  // 拷贝后自动安装依赖 
      };
    }
    

    接下来的目标是 : 在没有传入默认的语言参数下,让用户在命令行中选择参数.

    src/utils/promptForMissingOptions.js导出方法,代码如下

    import inquirer from "inquirer";
    import get from "lodash/get";
    export default async function promptForMissingOptions(options) {
      if (options.skipPrompts) {
        return {
          ...options,
          template: get(options, "template", "javascript")
        };
      }
    
      const questions = [];
      // 如果没有指定
      if (!options.template) {
        questions.push({
          type: "list",
          name: "template",
          message: "请选择壳工程语言",
          choices: ["javascript", "typescript"],
          default: "javascript"
        });
      }
    
      const answers = await inquirer.prompt(questions);
      return {
        ...options,
        template: get(options, "template", answers.template)
      };
    }
    

    src/cli.js中导出 cli 方法

    import parseArgumentsIntoOptions from "./utils/parseArgumentsIntoOptions";
    import promptForMissingOptions from "./utils/promptForMissingOptions";
    import get from "lodash/get";
    import pjson from "../package.json";
    import chalk from "chalk";
    
    export async function cli(args) {
      let options = parseArgumentsIntoOptions(args);
      // 打印版本信息
      if (get(options, "version")) {
        return console.log(chalk.green(`当前cli版本为 : ${pjson.version}`));
      }
      options = await promptForMissingOptions(options);
      console.log(options);
    }
    

    在命令行执行以下命令

    npm link 
    xh-cli
    

    则会出现命令行交互

    image-20201225105156614.png

    接下来的目标 : 执行上述命令交互后,根据所选项将项目复制到当前执行命令的路径上。

    我们在src/main.js中,增加以下代码

    import chalk from "chalk";
    import fs from "fs";
    // 用于递归复制文件
    import ncp from "ncp";
    import path from "path";
    import { promisify } from "util";
    import Listr from "listr";
    import { projectInstall } from "pkg-install";
    import get from "lodash/get";
    
    // 递归拷贝文件
    const copy = promisify(ncp);
    
    async function copyTemplateFiles(options) {
      return copy(options.templateDirectory, options.targetDirectory, {
        // 是否覆盖原有内容
        clobber: false
      });
    }
    
    export async function createProject(options) {
      options = {
        ...options,
        targetDirectory: get(
          options,
          "targetDirectory",
          path.resolve(process.cwd(), get(options, "template"))
        )
      };
    
      const currentFileUrl = import.meta.url;
    
      const templateDir = path.resolve(
        new URL(currentFileUrl).pathname.replace(/^\//, ""),
        "../../templates",
        options.template.toLowerCase()
      );
    
      options.templateDirectory = templateDir;
    
      const tasks = new Listr([
        {
          title: "拷贝中",
          task: () => copyTemplateFiles(options)
        },
        {
          title: "安装依赖",
          task: () =>
            projectInstall({
              cwd: options.targetDirectory
            }),
          skip: () =>
            !options.runInstall
              ? "Pass --install to automatically install dependencies"
              : undefined
        }
      ]);
    
      await tasks.run();
      console.log("%s Project ready", chalk.green.bold("DONE"));
      return true;
    }
    

    src/cli.js中增加以下代码

    import { createProject } from "./main";
    export async function cli(args) {
      // ...
      await createProject(options);
    }
    

    这样,cli工具的雏形已经完成了。

    四、运行

    template创建typescriptjavascript两个文件夹,并各自创建README.md文件

    ├─javascript
    └─typescript
    

    在任意目录下执行

    xh-cli
    

    选择任意一个,你看是不是复制成功了呢 ?

    image-20201225110252405.png

    当然,你通过以下命令在拷贝项目成功后添加依赖

    xh-cli --install
    

    最终,发布到npm 中

    npm publish 
    

    相关文章

      网友评论

          本文标题:Node.js 开发 cli 工具

          本文链接:https://www.haomeiwen.com/subject/jagbnktx.html