如何使用 yargs

什么是 Yargs

Yargs

Yargs 是一个很好的命令行程序库,简单地说,它可以让创建一个在控制台中运行的应用程序的过程变得轻而易举。还有什么能让它变得更好呢?它是以海盗为主题的(它的名字叫 YARgs),让它正式成为有史以来最好的工具。

你可能知道其他的 CLI,比如 vue-cli,可以轻松设置一个 Vue.js 项目或 create-react-app,所以这个概念对大多数人来说应该很熟悉。

开始

1
2
3
mkdir yargs_practice
cd yargs_practice
touch yargs.js

初始化项目, 并安装 yargs

1
2
npm init -y
npm i yargs

package.json 如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "name": "yargs_practice",
  "version": "1.0.0",
  "description": "",
  "main": "yargs.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "yargs": "^15.3.1"
  }
}

使用 vscode 打开当前目录

1
code .

编辑 yargs.js

1
2
3
const yargs = require("yargs");
const argv = yargs.argv;
console.log(argv);

在终端中运行

1
node yargs.js add --new thing --old="stuff"

得到如下结果

yargs

yard 可以很方便的拿到命令行参数

继续修改 yargs.js

1
2
3
4
5
const yargs = require("yargs");
const argv = yargs
  .command("add", "Add a new note")
  .command("list", "List all notes")
  .help().argv;
  • command 可以增加命令行信息
  • help 方法可以显示帮助信息

在终端中运行

1
node yargs.js --help

显示如下信息

yargs

yargs 提供了快捷命令方法(alias)让一些命令更简洁

继续修改 yargs.js

1
2
3
4
5
6
const yargs = require("yargs");
const argv = yargs
  .command("add", "Add a new note")
  .command("list", "List all notes")
  .help()
  .alias("help", "h").argv;

在终端中运行

1
node yargs.js -h

会得到和--help 一样的结果

TODO:: option 没看明白

1
2
3
4
5
6
const yargs = require("yargs");
const argv = yargs
  .command("add", "Add a new note")
  .command("list", "List all notes")
  .help()
  .alias("help", "h").argv;

option

yargs 还支持子命令 用法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const yargs = require("yargs");
const argv = yargs
  .command("add", "Add a new note", {
    title: {
      describe: "Title of note",
      alias: "t",
      demandOption: true,
    },
    body: {
      describe: "Body of note",
      alias: "b",
      demandOption: true,
    },
  })
  .command("list", "List all notes")
  .help()
  .option("find")
  .alias("help", "h").argv;

add 这个命令增加了子命令 title

  • describe 是这条命令的描述
  • alias 是这条命令的简写
  • demandOption 表示 title 必须传递参数

当我们在终端中执行

1
node yargs.js add -h

yargs

注意这里有别于 node yargs.js -h 这里展示的是 add 这条命令的具体帮助信息

实例

我们通过一个小的实例来看 yargs 如何使用

我们需要对这个package.json文件做一些调整,因为我们要创建一个 CLI。现在看起来应该是这样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "name": "yargs_practice",
  "version": "1.0.0",
  "description": "",
  "main": "yargs.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "bin": {
    "line-count": "./line-count"
  },
  "keywords": ["cli"],
  "preferGlobal": true,
  "author": "",
  "license": "ISC",
  "dependencies": {
    "yargs": "^15.3.1"
  }
}

以下是需要注意的重要改动。

我们添加了一个 bin 值,它将我们稍后创建的条目文件映射到它的可执行文件名上(你可以设置为任何你想要的名字
我们已经将 preferGlobal 设置为 true,这意味着我们的软件包希望被全局安装(例如通过 npm install -g)。
其他的调整包括改变描述、删除已使用的脚本、添加作者名称等。

创建一个基本的 CLI

Yargs 让解析命令行参数变得非常简单,很多例子项目可以在这里找到。

我们将创建一个基本的 CLI,它可以接收一个文件作为参数并计算它的行数。

要做到这一点,首先创建一个主脚本文件。

1
touch line-count

编辑这个文件

1
2
3
4
5
#!/usr/bin/env node
const argv = require("yargs")
  .usage("Usage: $0 <command> [options]")
  .help("h")
  .alias("h", "help").argv;

让我们把所有的代码逐条逐句的说说。

  1. #!/usr/bin/env node 是一个 shebang 行的实例,它告诉我们的系统用什么解释器来执行该文件
  2. .usage('Usage: $0 [options]')设置当调用 --help 命令时将显示的 CLI 的用法信息。
  3. .help('h') 将帮助命令绑定到选项 h 上。
  4. .alias('h', 'help') 为选项 -h 创建了一个别名,即 --help

与你所见,这第一步是非常简单的,yargs 的语法很直观。

接下来我们要添加count命令。

只需在你已有的 CLI 中添加以下几行。

1
2
3
.command("count", "Count the lines in a file")
.example("$0 count -f foo.js",
  "count the lines in the given file")

逐行看看:

  1. .command("count", "count the lines in a file") 创建了一个新的命令,名称为 count,并设置了一个描述。

  2. .example("$0 count -f foo.js", "count the lines in the given file") 创建一个带有描述的例子,当用户调用 --help 选项或者当他们忘记这个命令时,它将显示出来。

这些都很好,但现在运行node line-count计数并没有什么作用,接下来我们需要一个文件名,通过计数并显示其行数来完成 CLI。

添加如下信息

1
2
3
4
.alias("f", "file")
.nargs("f", 1)
.describe("f", "Load a file")
.demandOption(["f"])

line-count 最后应该是这样的样子。

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/env node
const argv = require("yargs")
  .usage("Usage: $0 <command> [options]")
  .command("count", "Count the lines in a file")
  .example("$0 count -f foo.js", "count the lines in the given file")
  .alias("f", "file")
  .nargs("f", 1)
  .describe("f", "Load a file")
  .demandOption(["f"])
  .help("h")
  .alias("h", "help").argv;

逐行,解释下新添加的代码

  1. .alias("f", "file") 为-f 选项创建别名 --file。

  2. .nargs("f", 1) 为该选项设置一个参数(文件名),否则显示 --help 菜单。

  3. .description("f", "Load a file")为该选项添加一个描述。

  4. .demandOption([["f"]),因为我们需要一个文件名,所以我们要求选项-f。

最后,让我们把程序的逻辑加上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Create stream with the file
const s = fs.createReadStream(argv.file);

var lines = 0;
s.on("data", (buf) => {
  // Get the number of lines
  lines += buf.toString().match(/\
/g).length;
});

s.on("end", () => {
  // Display the number of lines
  console.log(lines);
});

就这样,我们来试试。

createReadStream

到现在为止,我们的程序一直是这样运行的,但如果直接调用它,就会报错。

line-count

我们可以通过使用 npm link 命令将二进制文件(我们之前在 package.json 中定义为 bin)进行全局注册来解决这个问题。

在当前目录下执行

1
npm link

恭喜 ??,你现在可以像这样在本地运行你的脚本了。

1
line-count count -f package.json

line-count

发布 CLI 到 NPM

在部署之前,我们需要在 package.json 中添加一些信息。

1
2
3
4
5
6
7
8
"homepage": "YOUR GITHUB REPO OR SITE HERE",
"repository": {
  "type": "git",
  "url": "git+YOUR GITHUB REPOSITORY HERE"
},
"engines": {
  "node": ">=8"
},
  • homepage 和 repository 要填写你自己的 GitHub 项目地址
  • engines 确认 nodejs 版本号,简单地定义了你的项目应该在最小版本的节点上工作。 版本号取决于你用了那些版本的特性。

下面是接下来的步骤。

  • npmjs.com 上创建一个账户(可选,如果有可以忽略)
  • 运行 npm login 命令并输入你的信息
  • 运行 npm publish 命令,它将在几分钟内自动发布。

就是这样! 如果你想在将来更新你的项目,你需要在 package.json 文件中修改它的版本号,然后再次运行发布命令。

参考

  1. Building a CLI with Yargs
  2. How to use Yargs