记录一次命令行工具编写

546 阅读5分钟

工作中遇到这么一个场景

管理后台需要进行精确权限控制,比如页面,接口等等,需要在权限管理页面一个个手动添加页面以及各个页面使用的接口,甚至还有各个页面的按钮权限。这就导致一些问题

  1. 当前次开发新增很多页面以及接口时,手动添加是一件很麻烦的事情,还比较考验眼力,一不小心就配错了
  2. 环境迁移,测试环境,预发布环境,还有正式环境数据库都是隔离的,这就导致切换环境时需要重新配置,工作量巨大,费事费力

思考方案

实现一个命令行工具

  1. 提供一个配置模板
  2. 添加op时,执行初始化命令create-op -i,拷贝这个配置模板,更改成自己本次需要创建的内容
  3. 执行create-op -c env 实现不同环境下的op创建

创建op就具体业务具体分析了,无非就是根据配置,组装接口需要数据,然后依次手动调用接口即可,这里不做更多展开

实现

创建项目

npm init 初始化项目,-y或--yes,指定项目走默认配置

创建可执行脚本

创建一个bin文件夹,用来存放可执行命令对应的文件

创建可执行命令文件

#!/usr/bin/env node

#! /usr/bin/env node        首行shebang语句,指定使用node解释程序执行脚本。 在不同的操作系统中,node [命令行]的位置不同,因此使用 env node 找到路径并执行

image.png

注册命令行命令,这一步是很重要的

当我们创建好bin文件后,会发现我们此时是可以直接执行这个文件的

image.png

image.png

那我们每次需要执行这个脚本时都要找到这个脚本的位置,显然是不太方便的。那我们应该怎么做呢?创建软链 如下所示在package.json 中添加bin字段映射命令关键字与可执行文件

{
  ...
  "bin": {
    "create-op": "./bin/index.js"
  },
  ...
}

然后使用npm link安装本地模块,你就可以在{prefix}文件夹下看到你的命令了,当然这是因为我们现在是在本地开发模式下使用的这个方法

真正的开发中我们都是通过 npm install -g 或者 npm install安装远程模块的。在通过npm install -g全局安装的时候,npm会symlink可执行文件到{prefix}文件夹(Windows系统),npm install本地安装时,npm会symlink可执行文件到./node_modules/.bin 文件夹

可以使用npm prefix -g查看你的prefix目录

image.png

到这一步你就可以在任意位置打开命令行窗口,然后使用自己的命令了

如果想要取消软链,使用npm unlink -g <指令>的方式,当然你也可以去prefix文件夹下手动删除文件

image.png

命令行参数处理

此时就需要处理用户输入了,用户输入的就是命令行参数

console.log(process.argv);

image.png process为node进程中的全局变量,process.argv为一数组,数组内存储着命令行的各个部分,argv[0]为node的安装路径,argv[1]为主模块文件路径,剩下为子命令或参数。

看一个简单的例子

#!/usr/bin/env node

const pkg = require('../package.json');
const opt = process.argv[2];
switch (opt) {
    case '-v':
        console.log(pkg.version);
        break;
}

image.png

开发中简单使用process.argv搭配switch使用确实可以解决不少问题,但是如果工具功能越来越丰富可能就会面临参数过多,顺序不固定,甚至不知道取第几个参数的问题也会出现

此时需要引入一个专门处理命令行参数的包了,这里以commander库为例

具体使用可以参考官网,这里举个例子

const pkg = require('../package.json')
const { program } = require('commander');

// const { creatOp, creatOpInit } = require('../tool/index')

program
  .version(pkg.version)
  .option('-i, --init', '初始化op文件')
  .option('-c, --create <env>', '根据环境和op配置文件创建op')
  .action(opts => {
    // 约定初始化文件
    if (opts.init) {
      console.log('处理初始化op文件')
      // creatOpInit()
    }
    if (opts.create) {
      console.log('处理根据环境和op配置文件创建op')
      // creatOp()
    }
  })

  
program.parse();

image.png

命令行终端交互

咱们这个命令行工具只需要指令,没有与用户交互相关

当然你也可以搞得高级一些,比如预定义一些环境让用户选择

const inquirer = require('inquirer')

  const questions = [{
    type: 'list',
    message: '请选择环境:',
    name: 'env',
    choices: [
      "dev",
      "fat",
      "uat"
    ]
}]

inquirer
  .prompt(
    questions
  )
  .then(answers => {
    console.log(JSON.stringify(answers,null,'  '))
  })
  .catch(error => {
    if (error.isTtyError) {
        console.log('isTtyError: ',error)
    } else {
        console.log('Others err: ',error)
    }
  })

image.png

发布npm包

现在命令行工具写好了,需要给别的同事也使用怎么办呢

总不能直接把代码包发过去,然后让同事npm link吧。所以就需要把命令行工具发布到npm源上去,同事就能npm install了,而且以后代码更新同步问题也变得简单了

登录

npm login登录得时候可能会遇到这个问题

npm notice Beginning October 4, 2021, all connections to the npm registry - including for package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog for more information: github.blog/2021-08-23-…

检查自己的源,是否是https地址

npm源地址

因为我们要发布到官方源上面,所以要确保源地址为官方地址https://registry.npmjs.com

可以通过 npm config get registry 命令查看当前 registry 源。 如需修改 registry 可通过以下四种方式:

  • 在全局配置 .npmrc ,可通过命令 npm config set registry= https://registry.npmjs.org/ 
  • 在当前项目配置,在当前项目中添加配置文件 .npmrc 
registry = https://registry.npmjs.org/
  • 发布包时指定 --registry 选项,npm publish —registry=https://registry.npmjs.org/
  • 在当前项目的 package.json 中通过 publishConfig 字段指定。
 "publicConfig": {
    "registry": "https://registry.npmjs.org/"
  }

发布

npm publish --access public

通过命令行选项 --access public 声明为公有包