前端架构师-week4-通用脚手架命令Command类封装
目录
通用脚手架命令Command类封装
脚手架参数初始化方法开发
利用Node多进程动态执行命令(stdio的inherit属性讲解)
生成Node多进程动态执行代码
windows操作系统spawn执行命令兼容
通用脚手架命令Command类封装
lerna create @imooc-cli-dev/command 命令抽象包
记得改入口文件名字为 index.js
放置在 models 中
commands/init/lib/index.js 中 继承上面的 command类,记得 注册 和 npm install
脚手架参数初始化方法开发
每个异步队列的异常都需要单独捕获。
// models/command/lib/index.js 文件内容
'use strict';
const semver = require('semver');
const colors = require('colors/safe');
const log = require('@imooc-cli-dev/log');
const LOWEST_NODE_VERSION = '12.0.0';
class Command {
constructor(argv) {
// log.verbose('Command constructor', argv);
if (!argv) { // 参数健壮性判断
throw new Error('参数不能为空!');
}
if (!Array.isArray(argv)) {
throw new Error('参数必须为数组!');
}
if (argv.length < 1) {
throw new Error('参数列表为空!');
}
this._argv = argv;
let runner = new Promise((resolve, reject) => {
let chain = Promise.resolve();
chain = chain.then(() => this.checkNodeVersion()); // 运行命令前准备
chain = chain.then(() => this.initArgs());
chain = chain.then(() => this.init());
chain = chain.then(() => this.exec()); // 运行命令
chain.catch(err => {
log.error(err.message);
});
});
}
initArgs() {
this._cmd = this._argv[this._argv.length - 1];
this._argv = this._argv.slice(0, this._argv.length - 1);
}
checkNodeVersion() {
const currentVersion = process.version;
const lowestVersion = LOWEST_NODE_VERSION;
if (!semver.gte(currentVersion, lowestVersion)) {
throw new Error(colors.red(`imooc-cli 需要安装 v${lowestVersion} 以上版本的 Node.js`));
}
}
init() {
throw new Error('init必须实现!');
}
exec() {
throw new Error('exec必须实现!');
}
}
module.exports = Command;
// commands/init/lib/index.js 文件内容
'use strict';
const Command = require('@imooc-cli-dev/command');
const log = require('@imooc-cli-dev/log');
class InitCommand extends Command {
init() {
this.projectName = this._argv[0] || '';
this.force = !!this._cmd.force;
log.verbose('projectName', this.projectName);
log.verbose('force', this.force);
}
async exec() {
}
}
function init(argv) {
return new InitCommand(argv);
}
module.exports = init;
module.exports.InitCommand = InitCommand;
利用Node多进程动态执行命令(stdio的inherit属性讲解)
const child = spawn('node', ['-e', code], {
cwd: process.cwd(),
stdio: 'inherit',
});
// stdio: 'inherit' 父进程代码无需监听 stdxx ,直接把结果打印出来
child.on('error', e => {
log.error(e.message);
process.exit(1);
});
child.on('exit', e => {
log.verbose('命令执行成功:' + e);
process.exit(e); // 会打印 0
});
生成Node多进程动态执行代码
const args = Array.from(arguments);
const cmd = args[args.length - 1];
const o = Object.create(null); // 没有原型的对象,体积小
Object.keys(cmd).forEach(key => {
if (cmd.hasOwnProperty(key) && // 非原型属性
!key.startsWith('_') && // _ 通常表示私有属性
key !== 'parent') {
o[key] = cmd[key];
}
});
args[args.length - 1] = o;
const code = `require('${rootFile}').call(null, ${JSON.stringify(args)})`;
// 拼接上节代码
windows操作系统spawn执行命令兼容
function exec(command, args, options) {
const win32 = process.platform === 'win32';
const cmd = win32 ? 'cmd' : command;
// -c 表示静默执行
const cmdArgs = win32 ? ['/c'].concat(command, args) : args;
return require('child_process').spawn(cmd, cmdArgs, options || {});
}