const sleep = x => new Promise(res => setTimeout(() => res(), x * 1000)) ;(async () => { const { spawn } = require('node:child_process') const ora = (await import('ora')).default class Builder { constructor() { this.spinner = ora('Starting build').start() this.contextMaxLines = 3 this.contextLines = Array(this.contextMaxLines).fill('') this.allLines = [] this.steps = [] this.renderLines() } pushLine(line) { if ( this.contextLines.length >= this.contextMaxLines ) this.contextLines = this.contextLines.slice(1) this.contextLines.push(String(line).trimEnd()) this.allLines.push(String(line).trimEnd()) this.renderLines() } renderLines() { this.spinner.suffixText = `\n--\n${this.contextLines.join('\n')}\n--` } addStep(name, callback) { this.steps.push({ name, callback }) } async build() { for ( let i = 0; i < this.steps.length; i += 1 ) { const step = this.steps[i] this.spinner.text = `(${i+1}/${this.steps.length}) ${step.name}` await step.callback(this) } this.spinner.suffixText = '' this.spinner.succeed('Built successfully') } async executeOrExit(prog, ...args) { try { return await this.execute(prog, ...args) } catch (e) { this.spinner.suffixText = '' this.spinner.fail(`${this.spinner.text} - ${e.message}`) console.log(this.allLines.join('\n')) process.exit(1) } } execute(prog, ...args) { this.pushLine(`> ${prog} ${args.join(' ')}`) const cmd = spawn(prog, args) let output = '' cmd.stdout.on('data', data => { output += data String(data).split('\n').map(x => this.pushLine(x)) }) cmd.stderr.on('data', data => { output += data String(data).split('\n').map(x => this.pushLine(x)) }) return new Promise((res, rej) => { cmd.on('close', code => { if ( code ) { return rej(new Error('Process exited with code: ' + code)) } else { res(output.trim()) } }) }) } } const b= new Builder b.addStep( 'Remove old build files', b => b.executeOrExit('./node_modules/.bin/rimraf', 'lib'), ) b.addStep( 'Build back-end TypeScript code', b => b.executeOrExit('./node_modules/.bin/tsc', '-p', 'tsconfig.node.json'), ) b.addStep( 'Copy resources to output bundle', b => b.executeOrExit('./node_modules/.bin/fse', 'copy', '--all', '--dereference', '--preserveTimestamps', '--keepExisting=false', '--quiet', '--errorOnExist=false', 'src/app/resources', 'lib/app/resources'), ) b.addStep( 'Build front-end TypeScript code', b => b.executeOrExit('./node_modules/.bin/tsc', '-p', 'tsconfig.client.json'), ) b.addStep( 'Create front-end output bundle', b => b.executeOrExit('./node_modules/.bin/webpack', '--config', 'webpack.config.js'), ) await b.build() })();