UNPKG

phecda-server

Version:

server framework that provide IOC/type-reuse/http&rpc-adaptor

263 lines (222 loc) 6.46 kB
#! /usr/bin/env node import { fork } from 'child_process' import { createRequire } from 'module' import pc from 'picocolors' import cac from 'cac' import fse from 'fs-extra' import { log as psLog } from '../dist/index.mjs' const log = (...args) => { if (process.env.PS_BAN_CLI_LOG) return psLog(...args) } const cli = cac('phecda').option('-c,--config <config>', 'config file', { default: 'ps.json', }).option('-n,--node-args <node-args>', 'args that will be passed to nodejs', { default: '', }) const require = createRequire(import.meta.url) let child let closePromise const nodeVersion = parseFloat(process.version.slice(1)) if (nodeVersion < 18.19) { log( `Nodejs version less than 18.19(current is ${nodeVersion}) can't support hmr`, 'yellow', ) } function startChild(file, args) { child = globalThis.PS_CREATE_CHILD?.() || fork(file, { env: { ...process.env }, stdio: 'inherit', execArgv: [ ...args, nodeVersion < 18.19 ? '--loader=phecda-server/register/loader.mjs' : '--import=phecda-server/register', ], }) closePromise = new Promise((resolve) => { child.once('exit', (code) => { if (code === 4171) startChild(file, args) if (code === 4172) return process.exit() child = undefined resolve() }) }) } function exit() { log('process exit') if (child) { child.kill() process.exit(0) } else { process.exit(0) } } process.on('SIGINT', () => { process.exit() }) cli .command('init [root]', 'init config file') // .allowUnknownOptions() .option('-t,--tsconfig <tsconfig>', 'init tsconfig file', { default: 'tsconfig.json', }) .action(async (root, options) => { if (root) process.chdir(root) let hasUnimport try { await import('unimport') hasUnimport = true } catch (e) { hasUnimport = false } if (hasUnimport) { try { await import('phecda-core') } catch (e) { log('please install \'phecda-core\' when using unimport', 'warn') } } const tsconfigPath = options.tsconfig const psconfigPath = process.env.PS_CONFIG_FILE || options.config if (!fse.existsSync(tsconfigPath)) { log(`create ${tsconfigPath}`) await fse.outputJSON( tsconfigPath, { compilerOptions: { target: 'esnext', useDefineForClassFields: false, experimentalDecorators: true, emitDecoratorMetadata: true, module: 'esnext', lib: ['esnext', 'DOM'], paths: { }, strictPropertyInitialization: false, moduleResolution: 'bundler', strict: true, resolveJsonModule: true, esModuleInterop: true, noEmit: true, noUnusedLocals: true, noUnusedParameters: true, noImplicitReturns: true, skipLibCheck: true, }, include: ['.', hasUnimport ? (process.env.PS_DTS_PATH || 'ps.d.ts') : false].filter(Boolean), }, ) } if (!fse.existsSync(psconfigPath)) { log(`create ${psconfigPath}`) await fse.outputJSON(psconfigPath, { $schema: './node_modules/phecda-server/assets/schema.json', resolve: [ { source: 'controller', importer: 'http', path: '.ps/http.js', }, { source: 'rpc', importer: 'client', path: '.ps/rpc.js', }, ], unimport: hasUnimport && { dirs: [ ], presets: [ { package: 'phecda-server' } ], dirsScanOptions: { filePatterns: [ '*.{service,controller,module,rpc,solo,guard,extension,pipe,filter,addon}.ts', ], }, }, moduleFile: [], }) } log('init finish') }) cli .command('<file> [root]', 'run file') .alias('run') // .allowUnknownOptions() .option('-p,--prod', 'prod mode', { default: false, }) .action((file, root, options) => { const nodeArgs = options.nodeArgs.split(' ').filter(Boolean) if (root) process.chdir(root) if (options.prod) process.env.NODE_ENV = 'production' else process.env.NODE_ENV = 'development' process.env.PS_CONFIG_FILE = process.env.PS_CONFIG_FILE || options.config log('process start!') startChild(file, nodeArgs) console.log(`${pc.green('->')} press ${pc.green('e')} to exit`) console.log(`${pc.green('->')} press ${pc.green('r')} to relaunch`) console.log(`${pc.green('->')} press ${pc.green('c')} to clear terminal`) console.log(`${pc.green('->')} press ${pc.green('i')} to debug`) process.stdin.on('data', async (data) => { const args = [...nodeArgs] const input = data.toString().trim().toLocaleLowerCase() if (input === 'r') { if (child) { await child.kill() if (closePromise) await closePromise log('relaunch...') startChild(file, args) } else { log('relaunch...') startChild(file, args) } } if (input === 'e') exit() if (input === 'c') console.clear() if (input === 'i' || input.startsWith('i ')) { const [, arg] = input.split(' ') if (child) { child.send({ type: 'inspect', arg }) } else { args.push(`--inspect${arg ? `=${arg}` : ''}`) startChild(file, args) } } }) }) cli .command('generate <file> [root]', 'generate code(mainly for ci)') // .allowUnknownOptions() .action((file, root, options) => { const nodeArgs = options.nodeArgs.split(' ').filter(Boolean) if (root) process.chdir(root) process.env.PS_GENERATE = 'true' process.env.PS_CONFIG_FILE = process.env.PS_CONFIG_FILE || options.config startChild(file, nodeArgs) }) cli.help() cli.version(require('../package.json').version) cli.parse()