一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
脚手架之命令注册和执行过程开发
将收获什么
- 如何设计一个高性能脚手架
Node
多进程开发JavaScript
对面对象的实战技巧Node
多进程原理
主要内容
-
图解高性能脚手架架构设计方法
-
封装通用的
Command
和Package
类 -
基于缓存 +
Node
多进程实现动态命令加载和执行 -
将业务逻辑和脚手架逻辑彻底解耦
-
Node
多进程child_process
源码分析
关键词
-
高性能/可扩展的脚手架 - 利用缓存提升脚手架性能并解耦业务逻辑
-
面向对象 - 利用
Class
完成JavaScript
面向对象编程 -
Node
多进程 - 深入Node
多进程原理
注册命令
安装依赖
lerna add commander core/cli/
复制代码
// core\cli\lib\index.js
// 引入封装的 init 命令
const init = require('@hzw-cli-dev/init');
// 创建一个 commander 实例
const program = new commander.Command();
/**
* @description: 注册命令
* @param {*}
* @return {*}
*/
function registerCommand() {
// 注册 debug 模式
program
.name(Object.keys(pkg.bin)[0])
.usage('<command> [options]')
.version(pkg.version)
.option('-D, --debug', '是否开启调试模式', false);
// 注册命令
program
.command('init [projectName]')
.option('-f, --force', '是否强制初始化项目')
.action(init);
// 获取参数
const params = program.opts();
// 注册 debug 命令
program.on('option:debug', () => {
if (params.debug) {
process.env.LOG_LEVEL = 'verbose';
} else {
process.env.LOG_LEVEL = 'info';
}
// 设置 log 的等级
log.level = process.env.LOG_LEVEL;
log.verbose('test debug');
});
// 监听未注册的所有命令
program.on('command:*', (obj) => {
const commands = program.commands.map((cmd) => cmd.name());
log.info(colors.red('未知的命令 ' + obj[0]));
if (commands.length > 0) {
log.info(colors.blue('支持的命令 ' + commands.join(',')));
}
});
//解析参数
program.parse(process.argv);
// 判断是否输入命令 显示帮助文档
if (program.args && program.args.length < 1) {
program.outputHelp();
console.log();
}
}
复制代码
新建一个包,把 init
命令的业务代码抽离处理,方便后续维护。
lerna create @hzw-cli-dev/init
复制代码
// command\init\lib\index.js
function init(projectName, cmdObj) {
console.log('init', projectName, cmdObj);
}
module.exports = init;
复制代码
当前脚手架架构痛点分析
当前脚手架架构如下图
这样的架构设计已经可以满足一般的脚手架需求,但是有以下的问题
- 脚手架安装速度慢: 所有
package
都集成在cli
里,因此当命令较多时,会减慢脚手架的安装速度。 - 灵活性差:
init
命令只能使用@hzw-cli-dev/init
包,对于大公司而言,每个团队的init
命令可能都各不相同,可能需要init
命令动态化,如:-
A 团队使用
@hzw-cli-dev/init-a
作为初始化模块 -
B 团队使用
@hzw-cli-dev/init-b
作为初始化模块 -
C 团队使用
@hzw-cli-dev/init-c
作为初始化模块
-
这个时候对我们的架构设计提出了挑战,要求我们能够动态加载 init
模块,这将增加架构的复杂度,但大大提升脚手架的可扩展性,将脚手架框架和业务逻辑解耦。
脚手架架构优化
当前脚手架执行流程如下图
优化后流程图如下