腳手架框架之yargs高級(jí)應(yīng)用
1 )高級(jí)應(yīng)用概述
- 現(xiàn)在還用 xyzcli 這個(gè)腳手架,繼續(xù)在這個(gè)項(xiàng)目中來(lái)看yargs的高級(jí)用法
- 在 yargs 文檔中, 給出了復(fù)雜應(yīng)用的方式,這里做下詳解
- https://www.npmjs.com/package/yargs?activeTab=readme#complex-example
- 這里主要關(guān)注 ↓
command
recommendCommands
fail
2 )command 應(yīng)用案例
2.1 官方示例
- 復(fù)雜應(yīng)用案例,自定義 command
#!/usr/bin/env node const yargs = require('yargs/yargs') const { hideBin } = require('yargs/helpers') yargs(hideBin(process.argv)) // 注意 command的 四個(gè)參數(shù) .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 的四個(gè)參數(shù)分別是
- 1 )command + options, 這里
serve [port]
- 這里的serve是自定義的命令,如: $
xyzcli serve
- 這里的
[port]
是 option,如: $xyzcli serve --port
- 這里的serve是自定義的命令,如: $
- 2 )描述,這里是
start the server
- 用于對(duì)前面命令和配置的補(bǔ)充描述
- 3 )builder函數(shù),這里是一個(gè)回調(diào)
- builder是指在運(yùn)行command之前做的一些事情
- 這里會(huì)傳入 yargs 對(duì)象
- 比如在這里可以定義在這個(gè) serve 命令中用到的 option
- 這里定義了一個(gè)port參數(shù),并給它一個(gè)5000的默認(rèn)值
- 4 )handler函數(shù),用于具體執(zhí)行 command 的行為
- 比如這個(gè) serve 命令啟動(dòng)了一個(gè)http的服務(wù)
- 這個(gè)http服務(wù)就在這個(gè) handler 函數(shù)中定義
- 1 )command + options, 這里
- 這里 command 的四個(gè)參數(shù)分別是
2.2 在xyzcli中配置, 這里接上文走一個(gè)全量的代碼
#!/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, // 這個(gè)就不會(huì)出現(xiàn)在提示中,但是可以作為開(kāi)發(fā)調(diào)試使用 --ci
})
.group(['debug'], '開(kāi)發(fā)選項(xiàng):')
.group(['registry'], '其他選項(xiàng):')
.command('init [name]', 'Init your project', (yargs) => {
yargs
.option('name', {
type: 'string',
describe: 'Name of a project',
alias: 'n',
})
}, (argv) => {
console.log(argv);
})
.argv;
- 執(zhí)行 $
xyzcli init
,查看輸出{ _: [ 'init' ], '$0': 'xyzcli' }
- 執(zhí)行 $
xyzcli init --name xx
,查看輸出{ _: [ 'init' ], name: 'xx', '$0': 'xyzcli' }
- 執(zhí)行 $
xyzcli init -h
,查看輸出xyzcli init [name] Init your project 開(kāi)發(fā)選項(xiàng): -d, --debug Bootstrap debug mode [布爾] 其他選項(xiàng): -r, --registry Define global registry [字符串] 選項(xiàng): -n, --name Name of a project [字符串] -h, --help 顯示幫助信息 [布爾] -v, --version 顯示版本號(hào) [布爾]
- 可見(jiàn)最上面出現(xiàn)一則幫助提示
xyzcli init [name] Init your project
- 可見(jiàn)最上面出現(xiàn)一則幫助提示
- 執(zhí)行
xyzcli init -d -r npm -n x-project
, 查看輸出{ _: [ 'init' ], // _ 里面就是注冊(cè)的 command 命令 // d 和 debug 存在這兩個(gè)option, 則為true d: true, debug: true, // r 和 registry 也同樣 r: 'npm', registry: 'npm', // n 是 name,項(xiàng)目名稱為 x-project n: 'x-project', name: 'x-project', // $0 就是腳手架命令 '$0': 'xyzcli' }
- 注意,這種定義下,注意 alias 別名不能重復(fù)
- 如果重復(fù),覆蓋了,就會(huì)出問(wèn)題
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 發(fā)現(xiàn)內(nèi)容很少
- 再次查看全局配置: 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;
- 可見(jiàn)這個(gè) command 是一個(gè)對(duì)象,對(duì)象里有4項(xiàng)參數(shù)
- 以上這個(gè),是 Lerna 對(duì)yargs的內(nèi)部應(yīng)用,同樣,在自己的腳手架中試驗(yàn)一下
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, // 這個(gè)就不會(huì)出現(xiàn)在提示中,但是可以作為開(kāi)發(fā)調(diào)試使用 --ci }) .group(['debug'], '開(kāi)發(fā)選項(xiàng):') .group(['registry'], '其他選項(xiàng):') .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;
- 執(zhí)行 $
xyzcli list
, 查看輸出{ _: [ 'list' ], '$0': 'xyzcli' }
- 執(zhí)行 $
xyzcli ls
, 查看輸出{ _: [ 'ls' ], '$0': 'xyzcli' }
- 執(zhí)行 $
xyzcli ll
, 查看輸出{ _: [ 'll' ], '$0': 'xyzcli' }
- 執(zhí)行 $
xyzcli la
, 查看輸出{ _: [ 'la' ], '$0': 'xyzcli' }
- 以上就是 command 的兩種用法
3 )recommendCommands 應(yīng)用案例
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, // 這個(gè)就不會(huì)出現(xiàn)在提示中,但是可以作為開(kāi)發(fā)調(diào)試使用 --ci
})
.group(['debug'], '開(kāi)發(fā)選項(xiàng):')
.group(['registry'], '其他選項(xiàng):')
.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()
之后, 嘗試執(zhí)行 $xyzcli l
, 查看輸出Usage: xyzcli [command] <options> 命令: xyzcli init [name] Init your project xyzcli list List local package [aliases: ls, la, ll] 開(kāi)發(fā)選項(xiàng): -d, --debug Bootstrap debug mode [布爾] 其他選項(xiàng): -r, --registry Define global registry [字符串] 選項(xiàng): -h, --help 顯示幫助信息 [布爾] -v, --version 顯示版本號(hào) [布爾] 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?
, 這個(gè)命令就是當(dāng)你輸入不全時(shí),嘗試對(duì)你進(jìn)行提醒
- 看這最后,
4 )fail 應(yīng)用案例
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, // 這個(gè)就不會(huì)出現(xiàn)在提示中,但是可以作為開(kāi)發(fā)調(diào)試使用 --ci
})
.group(['debug'], '開(kāi)發(fā)選項(xiàng):')
.group(['registry'], '其他選項(xiàng):')
.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;
-
嘗試執(zhí)行 $
xyzcli lxx
故意給一個(gè)沒(méi)有的命令,查看輸出結(jié)果文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-828161.htmlmsg: 是指 ls? err: undefined msg: 無(wú)法識(shí)別的選項(xiàng):lxx err: undefined
- 這里輸出了 2個(gè) msg, 兩個(gè) err, 這里 err 都是 undefined
- 在實(shí)際應(yīng)用中,參考 lerna, 如下
-
參考 lerna 中的應(yīng)用 https://github.com/lerna/lerna/blob/main/libs/core/src/lib/cli.ts#L18文章來(lái)源地址http://www.zghlxwxcb.cn/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); })
到了這里,關(guān)于前端架構(gòu): 腳手架框架之yargs高級(jí)應(yīng)用教程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!