脚手架框架之yargs高级应用
1 )高级应用概述
- 现在还用 xyzcli 这个脚手架,继续在这个项目中来看yargs的高级用法
- 在 yargs 文档中, 给出了复杂应用的方式,这里做下详解
- https://www.npmjs.com/package/yargs?activeTab=readme#complex-example
- 这里主要关注 ↓
command
recommendCommands
fail
2 )command 应用案例
2.1 官方示例
- 复杂应用案例,自定义 command
#!/usr/bin/env node const yargs = require('yargs/yargs') const { hideBin } = require('yargs/helpers') yargs(hideBin(process.argv)) // 注意 command的 四个参数 .command('serve [port]', 'start the server', (yargs) => { return yargs .positional('port', { describe: 'port to bind on', default: 5000 }) }, (argv) => { if (argv.verbose) console.info(`start server on :${argv.port}`) serve(argv.port) }) .option('verbose', { alias: 'v', type: 'boolean', description: 'Run with verbose logging' }) .parse()
- 这里 command 的四个参数分别是
- 1 )command + options, 这里
serve [port]
- 这里的serve是自定义的命令,如: $
xyzcli serve
- 这里的
[port]
是 option,如: $xyzcli serve --port
- 这里的serve是自定义的命令,如: $
- 2 )描述,这里是
start the server
- 用于对前面命令和配置的补充描述
- 3 )builder函数,这里是一个回调
- builder是指在运行command之前做的一些事情
- 这里会传入 yargs 对象
- 比如在这里可以定义在这个 serve 命令中用到的 option
- 这里定义了一个port参数,并给它一个5000的默认值
- 4 )handler函数,用于具体执行 command 的行为
- 比如这个 serve 命令启动了一个http的服务
- 这个http服务就在这个 handler 函数中定义
- 1 )command + options, 这里
- 这里 command 的四个参数分别是
2.2 在xyzcli中配置, 这里接上文走一个全量的代码
#!/usr/bin/env node
const yargs = require('yargs/yargs');
const { hideBin } = require('yargs/helpers');
const dedent = require('dedent');
const arg = hideBin(process.argv);
const cli = yargs(arg)
cli
.usage('Usage: xyzcli [command] <options>')
.demandCommand(1, 'A command is required. Pass --help to see all available commands and options.')
.strict()
.alias('h', 'help')
.alias('v', 'version')
// .alias('d', 'debug')
.wrap(cli.terminalWidth())
.epilogue(dedent`
Welcome to use xyzcli command line.
We hope you guys work happily every day!
For more information, please visit: https://xxx.com/xxx/xyzcli
`)
.options({
debug: {
type: 'boolean',
describe: 'Bootstrap debug mode',
alias: 'd' // 这里添加了,上面就可以忽略了,推荐写在这里
}
})
.option('registry', {
type: 'string',
describe: 'Define global registry',
alias: 'r',
// hidden: true, // 这个就不会出现在提示中,但是可以作为开发调试使用 --ci
})
.group(['debug'], '开发选项:')
.group(['registry'], '其他选项:')
.command('init [name]', 'Init your project', (yargs) => {
yargs
.option('name', {
type: 'string',
describe: 'Name of a project',
alias: 'n',
})
}, (argv) => {
console.log(argv);
})
.argv;
- 执行 $
xyzcli init
,查看输出{ _: [ 'init' ], '$0': 'xyzcli' }
- 执行 $
xyzcli init --name xx
,查看输出{ _: [ 'init' ], name: 'xx', '$0': 'xyzcli' }
- 执行 $
xyzcli init -h
,查看输出xyzcli init [name] Init your project 开发选项: -d, --debug Bootstrap debug mode [布尔] 其他选项: -r, --registry Define global registry [字符串] 选项: -n, --name Name of a project [字符串] -h, --help 显示帮助信息 [布尔] -v, --version 显示版本号 [布尔]
- 可见最上面出现一则帮助提示
xyzcli init [name] Init your project
- 可见最上面出现一则帮助提示
- 执行
xyzcli init -d -r npm -n x-project
, 查看输出{ _: [ 'init' ], // _ 里面就是注册的 command 命令 // d 和 debug 存在这两个option, 则为true d: true, debug: true, // r 和 registry 也同样 r: 'npm', registry: 'npm', // n 是 name,项目名称为 x-project n: 'x-project', name: 'x-project', // $0 就是脚手架命令 '$0': 'xyzcli' }
- 注意,这种定义下,注意 alias 别名不能重复
- 如果重复,覆盖了,就会出问题
2.3 参考 lerna 工程示例
- 参考:https://github.com/lerna/lerna/blob/main/packages/lerna/src/index.ts
// Bundled import { lernaCLI } from "@lerna/core"; import changedCmd from "@lerna/commands/changed/command"; import cleanCmd from "@lerna/commands/clean/command"; import diffCmd from "@lerna/commands/diff/command"; import execCmd from "@lerna/commands/exec/command"; import importCmd from "@lerna/commands/import/command"; import infoCmd from "@lerna/commands/info/command"; import initCmd from "@lerna/commands/init/command"; import listCmd from "@lerna/commands/list/command"; import publishCmd from "@lerna/commands/publish/command"; import runCmd from "@lerna/commands/run/command"; import versionCmd from "@lerna/commands/version/command"; import addCachingCmd from "./commands/add-caching/command"; import repairCmd from "./commands/repair/command"; import watchCmd from "./commands/watch/command"; // Evaluated at runtime to grab the current lerna version const pkg = require("../package.json"); module.exports = function main(argv: NodeJS.Process["argv"]) { const context = { lernaVersion: pkg.version, }; const cli = lernaCLI() .command(addCachingCmd) .command(changedCmd) .command(cleanCmd) .command(createCmd) .command(diffCmd) .command(execCmd) .command(importCmd) .command(infoCmd) .command(initCmd) .command(listCmd) .command(publishCmd) .command(repairCmd) .command(runCmd) .command(watchCmd) .command(versionCmd); applyLegacyPackageManagementCommands(cli); return cli.parse(argv, context); };
- 按照上述这种用法,找其中一条
.command(listCmd)
- 定位到
import listCmd from "@lerna/commands/list/command";
- https://github.com/lerna/lerna/blob/main/packages/lerna/src/commands/list/command.ts 发现内容很少
- 再次查看全局配置: https://github.com/lerna/lerna/blob/main/tsconfig.base.json
"@lerna/commands/list": ["libs/commands/list/src/index.ts"],
- 定位到这里 https://github.com/lerna/lerna/blob/main/libs/commands/list/src/command.ts
import { filterOptions, listableOptions } from "@lerna/core"; import type { CommandModule } from "yargs"; /** * @see https://github.com/yargs/yargs/blob/master/docs/advanced.md#providing-a-command-module */ const command: CommandModule = { command: "list", aliases: ["ls", "la", "ll"], describe: "List local packages", builder(yargs) { listableOptions(yargs); return filterOptions(yargs); }, async handler(argv) { return (await import(".")).factory(argv); }, }; export = command;
- 可见这个 command 是一个对象,对象里有4项参数
- 以上这个,是 Lerna 对yargs的内部应用,同样,在自己的脚手架中试验一下
const cli = yargs(arg) cli .usage('Usage: xyzcli [command] <options>') .demandCommand(1, 'A command is required. Pass --help to see all available commands and options.') .strict() .alias('h', 'help') .alias('v', 'version') // .alias('d', 'debug') .wrap(cli.terminalWidth()) .epilogue(dedent` Welcome to use xyzcli command line. We hope you guys work happily every day! For more information, please visit: https://xxx.com/xxx/xyzcli `) .options({ debug: { type: 'boolean', describe: 'Bootstrap debug mode', alias: 'd' // 这里添加了,上面就可以忽略了,推荐写在这里 } }) .option('registry', { type: 'string', describe: 'Define global registry', alias: 'r', // hidden: true, // 这个就不会出现在提示中,但是可以作为开发调试使用 --ci }) .group(['debug'], '开发选项:') .group(['registry'], '其他选项:') .command('init [name]', 'Init your project', (yargs) => { yargs .option('name', { type: 'string', describe: 'Name of a project', alias: 'n', }) }, (argv) => { console.log(argv); }) // 注意,这里 .command({ command: 'list', aliases: ['ls', 'la', 'll'], describe: 'List local package', builder: (yargs) => {}, handler: (argv) => { console.log(argv); } }) .argv;
- 执行 $
xyzcli list
, 查看输出{ _: [ 'list' ], '$0': 'xyzcli' }
- 执行 $
xyzcli ls
, 查看输出{ _: [ 'ls' ], '$0': 'xyzcli' }
- 执行 $
xyzcli ll
, 查看输出{ _: [ 'll' ], '$0': 'xyzcli' }
- 执行 $
xyzcli la
, 查看输出{ _: [ 'la' ], '$0': 'xyzcli' }
- 以上就是 command 的两种用法
3 )recommendCommands 应用案例
const cli = yargs(arg)
cli
.usage('Usage: xyzcli [command] <options>')
.demandCommand(1, 'A command is required. Pass --help to see all available commands and options.')
.strict()
.recommendCommands() // 注意这里
.alias('h', 'help')
.alias('v', 'version')
// .alias('d', 'debug')
.wrap(cli.terminalWidth())
.epilogue(dedent`
Welcome to use xyzcli command line.
We hope you guys work happily every day!
For more information, please visit: https://xxx.com/xxx/xyzcli
`)
.options({
debug: {
type: 'boolean',
describe: 'Bootstrap debug mode',
alias: 'd' // 这里添加了,上面就可以忽略了,推荐写在这里
}
})
.option('registry', {
type: 'string',
describe: 'Define global registry',
alias: 'r',
// hidden: true, // 这个就不会出现在提示中,但是可以作为开发调试使用 --ci
})
.group(['debug'], '开发选项:')
.group(['registry'], '其他选项:')
.command('init [name]', 'Init your project', (yargs) => {
yargs
.option('name', {
type: 'string',
describe: 'Name of a project',
alias: 'n',
})
}, (argv) => {
console.log(argv);
})
.command({
command: 'list',
aliases: ['ls', 'la', 'll'],
describe: 'List local package',
builder: (yargs) => {},
handler: (argv) => { console.log(argv); }
})
.argv;
- 上面加上
.recommendCommands()
之后, 尝试执行 $xyzcli l
, 查看输出Usage: xyzcli [command] <options> 命令: xyzcli init [name] Init your project xyzcli list List local package [aliases: ls, la, ll] 开发选项: -d, --debug Bootstrap debug mode [布尔] 其他选项: -r, --registry Define global registry [字符串] 选项: -h, --help 显示帮助信息 [布尔] -v, --version 显示版本号 [布尔] Welcome to use xyzcli command line. We hope you guys work happily every day! For more information, please visit: https://xxx.com/xxx/xyzcli 是指 ls?
- 看这最后,
是指 ls?
, 这个命令就是当你输入不全时,尝试对你进行提醒
- 看这最后,
4 )fail 应用案例
cli
.usage('Usage: xyzcli [command] <options>')
.demandCommand(1, 'A command is required. Pass --help to see all available commands and options.')
.strict()
.recommendCommands()
// 注意这里
.fail((msg, err) => {
console.log('msg: ', msg)
console.log('err: ', err)
})
.alias('h', 'help')
.alias('v', 'version')
// .alias('d', 'debug')
.wrap(cli.terminalWidth())
.epilogue(dedent`
Welcome to use xyzcli command line.
We hope you guys work happily every day!
For more information, please visit: https://xxx.com/xxx/xyzcli
`)
.options({
debug: {
type: 'boolean',
describe: 'Bootstrap debug mode',
alias: 'd' // 这里添加了,上面就可以忽略了,推荐写在这里
}
})
.option('registry', {
type: 'string',
describe: 'Define global registry',
alias: 'r',
// hidden: true, // 这个就不会出现在提示中,但是可以作为开发调试使用 --ci
})
.group(['debug'], '开发选项:')
.group(['registry'], '其他选项:')
.command('init [name]', 'Init your project', (yargs) => {
yargs
.option('name', {
type: 'string',
describe: 'Name of a project',
alias: 'n',
})
}, (argv) => {
console.log(argv);
})
.command({
command: 'list',
aliases: ['ls', 'la', 'll'],
describe: 'List local package',
builder: (yargs) => {},
handler: (argv) => { console.log(argv); }
})
.argv;
-
尝试执行 $
xyzcli lxx
故意给一个没有的命令,查看输出结果文章来源:https://www.toymoban.com/news/detail-828161.htmlmsg: 是指 ls? err: undefined msg: 无法识别的选项:lxx err: undefined
- 这里输出了 2个 msg, 两个 err, 这里 err 都是 undefined
- 在实际应用中,参考 lerna, 如下
-
参考 lerna 中的应用 https://github.com/lerna/lerna/blob/main/libs/core/src/lib/cli.ts#L18文章来源地址https://www.toymoban.com/news/detail-828161.html
.fail((msg, err: any) => { // certain yargs validations throw strings :P const actual = err || new Error(msg); // ValidationErrors are already logged, as are package errors if (actual.name !== "ValidationError" && !actual.pkg) { // the recommendCommands() message is too terse if (/Did you mean/.test(actual.message)) { // TODO: refactor to address type issues // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore log.error("lerna", `Unknown command "${cli.parsed.argv._[0]}"`); } log.error("lerna", actual.message); } // exit non-zero so the CLI can be usefully chained cli.exit(actual.exitCode > 0 ? actual.exitCode : 1, actual); })
到了这里,关于前端架构: 脚手架框架之yargs高级应用教程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!