@hsui/cli
Version:
Hundsun frontend framework CLI
209 lines (183 loc) • 7.31 kB
JavaScript
const chalk = require('chalk');
const inquirer = require('inquirer');
const spawn = require('cross-spawn');
const { Command } = require('commander');
const { name, version } = require('../package.json');
const {
PluginAPI,
loadService,
isHuiProject,
resolveUserOptions,
resolveUserPlugins,
spinner
} = require('@hsui/shared');
const hui = new Command('hui');
hui
.usage('<command> [options]')
.version(`${name} ${version}`, '-v, --version', '显示版本号')
.addHelpCommand(false)
.helpOption('-h, --help', '显示帮助信息')
.passCommandToAction(false);
hui
.command('create [name]')
.description('根据指定模板创建并初始化一个新的应用')
.option('-t, --boilerplate-type <boilerplateType>', '指定应用模板类型')
.action(async function (name, { boilerplateType }) {
// await assertRegistry();
const Service = await loadService('boilerplates', 'create');
new Service(resolveUserOptions({ name, boilerplateType })).run('create');
});
hui
.command('generate <path>')
.alias('g')
.description('在自动路由模式下生成一个新的视图组件')
.option('-o, --overwrite', '强制覆盖已经存在的文件或者目录')
.action(async function (path, { overwrite }) {
await assertProject();
const Service = await loadService('boilerplates', 'generate');
new Service(resolveUserOptions({ path, overwrite })).run('generate');
});
hui
.command('dev')
.description('启动开发环境的内置服务器')
.option('-p, --port <port>', '指定内置服务器端口', '8000')
.option('-b, --browser', '自动打开浏览器', false)
.option('--deps, --dependencies', '获取当前工程的运行时依赖信息', false)
.option('--inspect', '审查项目 webpack 配置', false)
.action(async function (args) {
// await assertRegistry();
await assertProject();
const Service = await loadService('bundler', 'dev');
const bundlerServiceInstance = new Service(resolveUserOptions(args));
process.HUI_CLI_BUNDLER_SERVICE = bundlerServiceInstance;
bundlerServiceInstance.run('dev');
});
hui
.command('build')
.description('执行生产环境的编译集成任务')
.option('--debug', '打开调试模式', false)
.option('-d, --dest <dir>', '指定打包文件目录', 'dist')
.option('--filename-hashing', '在生成的静态资源的文件名添加 hash 后缀', false)
.option('--lib, --lib-bundler', '资源构建集成,需要结合 libs 配置项', false)
.option('--module, --module-bundler [name]', '业务模块构建集成,支持指定具体的模块名称')
.option('--pro, --pro-bundler', '兼容 1.0 构建集成,以 index.pro.js 为打包入口', false)
.option('--see', '自动生成SEE发布物', false)
.option('--docker', '自动生成支持容器化部署的SEE发布物', false)
.option('--bundler <version>', '指定 bundler 版本', '')
.option('--deps, --dependencies', '获取当前工程的运行时依赖信息', false)
.option('--inspect', '审查项目 webpack 配置', false)
.action(async function (args) {
// await assertRegistry();
await assertProject();
try {
if (args.bundler) {
const { GlobalDepsManager } = require('../lib/GlobalDepsManager');
await new GlobalDepsManager('service').action({ upgrade: `bundler@${args.bundler}` });
}
const Service = await loadService('bundler', 'build');
const bundlerServiceInstance = new Service(resolveUserOptions(args));
process.HUI_CLI_BUNDLER_SERVICE = bundlerServiceInstance;
bundlerServiceInstance.run('build');
} catch (error) {
console.log(error);
process.exit(1);
}
});
hui
.command('serve <dir>')
.description('使用内置服务器为指定目录提供静态资源服务')
.option('--path <path>', '指定静态资源服务的路由地址', '/')
.option('--log', '开启访问日志', false)
.option('-p, --port <port>', '指定服务器端口', '9000')
.action(async function (dir, { path, log, port }) {
const Service = await loadService('server', 'serve');
new Service(resolveUserOptions({ dir, path, log, port })).run('serve');
});
hui
.command('boilerplate')
.description('查看和管理当前环境的应用模版')
.option('-a, --add <boilerplate-name>', '在当前环境下安装应用模版')
.option('-l, --list', '查看本地安装的应用模版')
.option('-r, --remove <boilerplate-name>', '删除本地安装的应用模版')
.option('-u, --upgrade [boilerplate-name]', '升级本地安装的应用模版,不指定参数将全部升级', 'all')
.action(async function (args) {
const { GlobalDepsManager } = require('../lib/GlobalDepsManager');
new GlobalDepsManager('boilerplate').action(args);
});
hui
.command('service')
.description('查看和管理当前环境的内置服务')
.option('-l, --list', '查看本地安装的内置服务和版本')
.option('-r, --remove <service-name>', '移除本地安装的内置服务')
.option('-u, --upgrade [service-name]', '升级本地安装的内置服务,不指定参数将全部升级', 'all')
.action(async function (args) {
const { GlobalDepsManager } = require('../lib/GlobalDepsManager');
new GlobalDepsManager('service').action(args);
});
// apply user commands
applyUserCommands();
hui.on('--help', () => {
console.log();
console.log(` 运行 ${chalk.cyan(`hui <command> --help`)} 获取更多帮助信息\n`);
console.log();
});
hui.commands.forEach((c) => c.on('--help', () => console.log()));
hui.parse(process.argv);
// 镜像地址检查
async function assertRegistry() {
let { stdout: registry } = spawn.sync('npm', ['config', 'get', 'registry']);
registry = registry.toString().trim();
if (/taobao/.test(registry) || /registry\.npmjs\.org/.test(registry)) {
const { okay } = await inquirer.prompt([
{
type: 'confirm',
name: 'okay',
message: `注意 HUI CLI 目前只在内网发布, 继续操作之前请指定一个合法的镜像地址, 你想继续吗?`,
default: false
}
]);
if (okay) return true;
process.exit(1);
}
}
// 项目检查
async function assertProject() {
if (!isHuiProject()) {
console.log();
spinner(`${chalk.redBright('这似乎不是一个 HUI2.0 的项目')}\n`).fail();
process.exit(1);
}
}
function applyUserCommands() {
const { commands } = applyUserPlugins();
Object.keys(commands).forEach((name) => {
const { fn, opts } = commands[name];
const { description, options } = opts;
const userCommand = new Command(name);
userCommand
.description(description)
.storeOptionsAsProperties(false)
.passCommandToAction(false)
.action(fn);
if (options) {
options.forEach(({ name, description, value }) => {
userCommand.option(name, description, value);
});
}
hui.addCommand(userCommand);
});
}
function applyUserPlugins() {
const service = {
commands: {}
};
// resolve user plugins
const plugins = resolveUserPlugins();
// apply plugins.
plugins.forEach(({ id, apply, options }) => {
apply = apply.default || apply;
apply(new PluginAPI(id, service), options);
});
return service;
}