美文网首页
制作 node 命令行!

制作 node 命令行!

作者: HoPGoldy | 来源:发表于2019-06-20 18:01 被阅读0次

    这篇文章是为了记录使用commander模块制作node命令行工具的经验以作备忘,请善用ctrl + f进行搜索。

    基本

    下面是几个commander模块最基本的 概念 或者 方法,最简单的命令行可以参考 github - 基本示例

    概念

    • commander 推荐链式调用写法。
    • 命令行工具有关的一般都写在项目根目录的bin目录下
    • 在命令行入口文件开头要加上#!/usr/bin/env node 来指定使用node运行
    • 可以直接以node 文件名.js [子命令] [参数]的形式使用命令行,下文会给出如何全局调用命令行

    基本方法

    • version('1.0.0') 设置版本: 接受一个字符串,设置当前工具的版本。
    • description('介绍') 设置介绍: 接受一个字符串,设置为当前命令的介绍。
    • parse(process.argv) 解析参数: 参数固定为process.argv,一般放在末尾。

    添加参数

    可以使用option()指定一个参数,如下:为命令行指定一个参数-t

    program
        .version('1.0.0')
        .description('这是一个命令行工具')
        .option('-t, --test [测试参数]', '输入测试参数')
    

    option()的第二个参数是参数的介绍,而第一个参数很重要,它指定了参数的两种写法、是否必填 以及 参数的名字。下面对第一个参数-t, --test [测试参数]进行下分析:

    • 参数写法 -t, --test
    • 是否必填 <>必填 或者 []选填,
    • 参数的名字 测试参数,这个填什么都行,用于让用户更加了解。

    参数使用

    当用户输入了一个参数之后该如何使用它呢?这就要用到action()方法了,这个方法指定了用户在调用了命令之后应执行的逻辑。而 用户输入的参数就包含在action回调的第一个参数里

    //app.js
    program
        .command('config')
        .description('配置')
        .option('-t, --test [测试参数]', '输入测试参数')
        .action(cmd => {
            console.log(cmd)
        })
    
    // 用户输入
    > node app.js config -t 123 
    // 输出
    > {
        ...
        test: 123,
      }
    

    要注意的是,如果这里不指定参数名-t直接追加参数值的话,action回调的参数cmd的值为就会被替换成追加的参数值,如下:

    // 用户输入
    > node app.js config helloworld 
    // 输出
    > helloworld
    

    添加子命令

    可以通过command()来快速添加一个子命令,该方法接受一个字符串参数,内容为该子命令的名字,并且可以通过链式调用快速完善一个子命令。

    program
        .command('config')
        .description('配置')
        .action(cmd => {
            console.log('配置')
        })
    

    全局命令行

    配置全局安装非常简单,首先确保命令行的入口文件的第一行是#!/usr/bin/env node,这个很关键。

    然后在package.json里添加bin字段,如下:这个auto-git就是全局安装之后你的命令行工具的名字,而后面的"bin/index.js"就是命令行工具的入口了,这个不一定是index.js,自己可以随便指定,但是第一行都要有#!/usr/bin/env node

    "bin": {
      "auto-git": "bin/index.js"
    },
    

    本地调试

    想要本地调试也很简单,直接在 项目根目录 下执行如下命令就好了:

    npm install . -g
    

    然后就可以在任意位置使用bin中指定的工具名字来使用命令行了,并且你修改代码后也无需重新安装即可使用。

    发布后的安装

    和本地调试的安装基本一样,不过.换成了你的package包名,然后就可以正常使用了。

    npm install <你的包名> -g
    

    这里有一点需要注意的是,package.json里的name字段指定的是你的包名,而 package.json里的bin字段才是命令行的名字

    子命令模式

    commander有一个模式叫做 子命令模式,可以把不同的子命令拆分在多个文件里来方便维护。这里写一下用法,可以参考例子 github - 子命令模式

    首先是启用子命令模式,在一般的写法中,使用command()注册子命令之后都会链式调用一个action()来添加调用子命令时触发的逻辑。只要 在使用command()之后没有调用action(),就可以启用子命令模式,如下:

    //app.js
    #!/usr/bin/env node
    const program = require('commander')
    
    program
        .version('1.0.0')
        .description('这是一个命令行工具')
        .option('-t, --test [测试参数]', '输入测试参数')
        .command('add', '添加')
        .parse(process.argv)
    

    可以看到,这里只使用command()注册了子命令而并没有设置其参数和逻辑,那这些内容应该写在哪里呢?子命令的内容应写在同级目录下的<主命令文件名>-<子命令名>.js。例如,上面例子中add子命令的内容就应该写在app-add.js中,如下:

    var program = require('commander')
    
    program
        .option('-t, --test [测试]', '测试参数')
        .action(cmd => cmdAction(cmd))
        .parse(process.argv)
    
    function cmdAction(cmd) {
        console.log('添加')
    }
    

    这样就可以正常使用子命令了,但是要注意以下两点:

    • 子命令文件中,program链式调用的最后一定要加上parse(process.argv),不然子命令会无法执行且不报任何错误
    • 子命令的文件只能放在同级目录下,没有这个文件的话会报下面这个错误:
      error: app-add(1) does not exist, try --help
      

    使用 json 保存配置项

    使用json来保存命令行的配置项还是比较常用的,但是类似的文章并没有找到太多,所以这里也简单写一下,可以参考例子 github - 保存配置文件

    这里用fspath模块来读写json文件,并且封装出了下面三个方法供其他文件使用:

    • init(): 放在最开始的地方,用于检测本地有没有设置文件setting.json,没有的话就新建该文件
    • load(): 读取setting.json中的数据并转化为js对象
    • save(): 将接受的参数保存到setting.json
    const fs = require('fs')
    const path = require('path')
    
    // 设置json保存的位置
    const settingFile = path.join(__dirname, 'setting.json')
    // 设置的初始模板
    const settingTempalte = {
        default: 'default value'
    }
    
    module.exports = {
        init: () => {
            try {
                fs.statSync(settingFile)
            }
            catch (e) {
                console.log('设置文件不存在, 已新建')
                save(settingTempalte)
            }
        }, 
        load: () => {
            return JSON.parse(fs.readFileSync(settingFile, 'utf8'))
        }, 
        save: (data) => {
            fs.writeFileSync(settingFile, JSON.stringify(data, null, 4))
        }
    }
    
    

    具体的调用方法可以在 例子 中找到。

    跟随 package.json 文件中的版本号

    因为commander需要通过version()来设置版本,这样在加上package.json里的版本就要修改两个地方,如果我们想让命令行工具的版本跟随package.json中的版本应该怎么做呢。很简单,也是使用fs模块就可以了。

    const fs = require('fs')
    const packageData = fs.readFileSync('./package.json', 'utf8')
    const packageVersion = JSON.parse(packageData).version
    
    program
        .version(packageVersion)
        ...
    

    参考

    相关文章

      网友评论

          本文标题:制作 node 命令行!

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