脚手架注册和命令注册
1 )脚手架的注册
- 接上文,仍旧在
abc-cli项目中 - 参考:https://blog.youkuaiyun.com/Tyro_java/article/details/136381086
- 之前初始化的时候,使用的是 yargs, 现在我们想要使用 commander
- 在cli包中安装 commander $
npm i commander -w @abc.com/cli - 进入 abc-cli/packages/cli/lib/inex.js
const commander = require('commander'); const { program } = commander; const pkg = require('../package.json'); module.exports = (args) => { program .name(Object.keys(pkg.bin)[0]) .usage('<command> [options]') .version(pkg.version) .option('-d, --debug', '是否开启调试模式', false) program.parse(process.argv) } - 在 cli 目录下执行 $
abc-cli -V验证可以正确输出版本 - 这样脚手架注册的默认流程实现了
2 )命令的注册
-
接着写这个程序
const commander = require('commander'); const { program } = commander; const pkg = require('../package.json'); module.exports = (args) => { program .name(Object.keys(pkg.bin)[0]) .usage('<command> [options]') .version(pkg.version) .option('-d, --debug', '是否开启调试模式', false) // 这里注册命令 program .command('init [name]') .description('init project') .option('-f, --force', '是否强制更新', false) .action((name, opts) => { console.log('init ...') console.log(name) console.log(opts) }) program.parse(process.argv) } -
验证下,在cli目录执行 $
abc-cli -h, 有如下返回Usage: abc-cli <command> [options] Options: -V, --version output the version number -d, --debug 是否开启调试模式 (default: false) -h, --help display help for command Commands: init [options] [name] init project help [command] display help for command- 可以看到 Commands 栏多了 init 命令
-
在cli目录下,执行 $
abc-cli init 666 -f,可看到init ... 666 { force: true }- 这里,name 和 opts 都拿到了,说明命令都注册成功了
封装 commander方法
-
上述commander的使用比较随意,commander是一个比较综合的框架
-
想要更好使用commander的API, 将commander二次封装很有必要
-
创建一个新的包,叫做 command,在 abc-cli 目录下,执行 $
lerna create commandname填入@abc.com/commandentry point填入lib/index.js
-
之后,abc-cli/packages/command/lib/command.js 改名叫 index.js
-
现在来修改编写这个 index.js
class Command { constructor(instance) { if (!instance) { throw new Error('command instance must exists!') } this.program = instance; this.program .command('init [name]') .description('init project') .option('-f, --force', '是否强制更新', false) .action((name, opts) => { console.log('init ...') console.log(name) console.log(opts) }) } get command() { throw new Error('command must be implements') } } module.exports = Command; -
现在注册另一个包,叫做 init, 用于初始化 xx,
-
在 abc-cli 目录下,执行$
lerna create initname填入@abc.com/initentry point填入lib/index.js
-
之后,abc-cli/packages/init/lib/init.js 改名叫 index.js, 并编辑如下
// 先搭建好结构 const Command = require('@abc.com/command') class InitCommand extends Command { // 这个方法必须自行实现,否则走默认会报错 get command() { return 'init [name]' } } function Init(instance) { return new InitCommand(instance); } module.exports = Init; -
编写好了之后,因为 init包需要 command 包
- 在 abc-cli 目录下,执行 $
npm i @abc.com/command -w packages/init
- 在 abc-cli 目录下,执行 $
-
同样,cli 包也需要 init 包,如下
- 在 abc-cli 目录下,执行 $
npm i @abc.com/init -w packages/cli
- 在 abc-cli 目录下,执行 $
-
现在编辑 abc-cli/packages/cli/lib/index.js
const commander = require('commander'); const createInitCommand = require('@abc.com/init'); const { program } = commander; const pkg = require('../package.json'); module.exports = (args) => { program .name(Object.keys(pkg.bin)[0]) .usage('<command> [options]') .version(pkg.version) .option('-d, --debug', '是否开启调试模式', false) createInitCommand(program); // 注册命令 program.parse(process.argv) } -
在 abc-cli 目录下,执行 $
abc-cli init sss, 返回init ... sss { force: false } -
目前,对 commander 的改造已经看到了初步的成果
-
在 abc-cli/packages/command/lib/index.js Command 类中
-
实现了 对
command这个 API 的约束,如果子类不实现,则会报错, -
同样,对 description 这个 API 也同样可以约束
-
下面就集中再次进行改造
// packages/command/lib/index.js 中的 Command 类的 constructor 改造 constructor(instance) { if (!instance) { throw new Error('command instance must exists!') } this.program = instance; const cmd = this.program.command(this.command); cmd.description(this.description); // 这里插入两个钩子函数 cmd.hook('preAction', () => { this.preAction(); }) cmd.hook('postAction', () => { this.postAction(); }) // 处理 option, 并支持多个 option if (this.options?.length > 0) { this.options.forEach(option => { cmd.option(...option); }) } cmd.action((...params) => { this.action(params); }) } // packages/command/lib/index.js 中的 Command 类中添加 get description() { throw new Error('description must be implements') } get options() { return []; } // 这里没有get action() { throw new Error('action must be implements') } preAction() { // empty } postAction() { // empty } // packages/init/lib/index.js 中添加 get description() { return 'init project' } get options() { return [ ['-f, --force', '是否强制更新', false], ['-d, --debug', '是否调试模式', false], ] } // 注意这里没有 get 修饰 action([name, opts]) { console.log('init ...') console.log(name) console.log(opts) } preAction() { console.log('pre'); } postAction() { console.log('post'); } -
在 abc-cli 下执行 $
abc-cli init sd, 查看返回pre init ... sd { force: false, debug: false } post -
这类开发模式,会带给你完全不同的开发体验
-
到目前,我们已经把这个 command 脚手架框架作为我们脚手架的一部分来协助我们开发脚手架
2222



被折叠的 条评论
为什么被折叠?



