05 学习搭建一个简易的cli工具

206 阅读2分钟

1. 步骤

  • 创建项目文件夹 create-web-frame
  • 在 create-web-frame 目录下执行 npm init -y 创建 package.json
  • 安装 commander、inquirer、execa、fs-extra 依赖包
  • 在 create-web-frame 文件夹下新建一个 bin 目录
  • 进入 bin 目录创建 create-web-frame.js文件
  • 编写 node.js 代码搭建cli工具
  • 发布到npm(省略)

2. 用到的库的简介

  • commander

       地址:www.npmjs.com/package/com…

       作用:用于解析progress.argv

  • process.argv

       process.argv 属性返回数组,其中包含启动 Node.js 进程时传入的命令行参数。 第一个 元素将是 process.execPath。 如果需要访问 argv[0] 的原始值,请参阅 process.argv0。第二个元素将是正在执行的 JavaScript 文件的路径。 其余元素将是任何其他命令行参数。

通过执行node create-web-frame.js打印console.log(process.argv)值如下:

[  'C:\\Program Files\\nodejs\\node.exe',  'C:\\Users\\86135\\Downloads\\create-web-frame\\bin\\create-web-frame.js',  'app',  '--port',  '3000']
  • inquirer

       地址:www.npmjs.com/package/inq…

       作用:实现交互式命令行用户界面

  • execa

       地址:www.npmjs.com/package/exe…

       作用:可以调用shell和本地外部程序的javascript封装。会启动子进程执行。

  • fs-extra

       地址:www.npmjs.com/package/fs-…

       作用:fs-extra 是 fs 的一个扩展,提供了非常多的便利 API,并且继承了 fs 所有方法和为 fs 方法添加了 promise 的支持。它应该是 fs 的替代品。

  • process.cwd() 方法返回 Node.js 进程的当前工作目录。

  • #!/usr/bin/env node:在写npm包的时候须要在脚本的第一行写上#!/usr/bin/env node ,用于指明该脚本文件要使用node来执行

3. 完整代码

#!/usr/bin/env nodeconst { program } = require("commander");const inquirer = require("inquirer");const execa = require("execa");const fse = require("fs-extra");/** * 引入package.json 文件,需要用到其中的 version 字段 */const packageJson = require("../package.json");program.version(packageJson.version)  .argument("[web-server-name]", "web server 应用名称,英文、数字、_、-组成")  .option("-f --force", "当项目已存在的时候强制创建项目")  .option("-p --port <port>", "项目端口", "8888")  .action(async (name, opts, command) => {    const options = {      rootDirectory: process.cwd(), // Current Work Directory      serverName: "app",      dependencies: ["koa", "nodemon", "minimist"]  // 默认安装的依赖    };

    // 问答内容
    let promptOpts = [      {        type: "checkbox",        name: "middlewares",        message: "请选择要安装的中间件",        choices: ["koa-static-cache", "koa-router", "koa-body"],        default: ["koa-static-cache", "koa-router"],      }    ];        if(name) {      options.serverName = name;    } else {      promptOpts.unshift({        type: "input",        name: "serverName",        message: "请输入应用名称",        default: "app",      })    }    if(opts) {      options.serverPort = opts.port;    } else {      promptOpts.unshift({        type: "input",        name: "serverPort",        message: "请输入应用端口",        default: 8888,      })    }    
    // res 为用户选择后的返回值
    const res = await inquirer.prompt(promptOpts);    options.serverName = res.serverName;    options.serverPort = res.serverPort;    options.rootDirectory += `/${res.serverName}`;    options.dependencies = [...options.dependencies, ...res.middlewares];    // 创建目录    fse.mkdirsSync(options.rootDirectory);    // 初始化    const cmdInit = `npm init -y`;    execa.commandSync(cmdInit, {      cwd: options.rootDirectory,    });    // 安装    const cmdInstall = `npm install ${options.dependencies.join(" ")}`;    execa.commandSync(cmdInstall, {      cwd: options.rootDirectory,      stdio: ["inherit", "inherit", "inherit"]    });    // 创建文件    const content = `      const minimist = require('minimist');      const Koa = require('koa');      const argv = minimist(process.argv.slice(2));      const app = new Koa();      app.use((ctx, next) => {          ctx.body = 'Hello';      });      app.listen(argv.port, () => {          console.log(\`服务启动成功:http://localhost:\${argv.port}\`);      });`;    const entryFile = options.rootDirectory + "/app.js";    fse.outputFileSync(entryFile, content, {      encoding: "utf-8",    });  });program.parse(process.argv);

4. 执行 node create-web-frame.js