UNPKG

@hsui/cli

Version:

Hundsun frontend framework CLI

209 lines (183 loc) 7.31 kB
#!/usr/bin/env node 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; }