@travetto/pack
Version:
Code packing utilities
162 lines (127 loc) • 4.88 kB
text/typescript
import os from 'node:os';
import path from 'node:path';
import { CliCommandShape, CliFlag, ParsedState, cliTpl } from '@travetto/cli';
import { TimeUtil, Runtime, RuntimeIndex } from '@travetto/runtime';
import { Terminal } from '@travetto/terminal';
import { Ignore, Required, Schema } from '@travetto/schema';
import { PackageUtil } from '@travetto/manifest';
import { PackOperation } from './bin/operation.ts';
import { PackUtil } from './bin/util.ts';
export type PackOperationShape<T> = ((config: T) => AsyncIterable<string[]>);
export abstract class BasePackCommand implements CliCommandShape {
static get entryPoints(): string[] {
return RuntimeIndex.find({
module: m => m.prod,
folder: f => f === 'support',
file: f => f.sourceFile.includes('entry.')
})
.map(x => x.import.replace(/[.][^.]+s$/, ''));
}
_parsed: ParsedState;
buildDir: string = path.resolve(os.tmpdir(), Runtime.mainSourcePath.replace(/[\/\\: ]/g, '_'));
clean = true;
output: string;
mainScripts: boolean = true;
mainName: string;
entryPoint: string = '@travetto/cli/support/entry.trv.ts';
minify = true;
sourcemap = false;
includeSources = false;
ejectFile?: string;
rollupConfiguration = '@travetto/pack/support/rollup/build.ts';
envFile = '.env';
manifestFile = 'manifest.json';
includeWorkspaceResources: boolean = false;
externalDependencies: string[] = [];
module: string;
mainFile: string;
/** Entry arguments */
entryArguments: string[] = [];
workspaceResourceFolder: string = 'resources-workspace';
getOperations(): PackOperationShape<this>[] {
return [
PackOperation.clean,
PackOperation.writeEnv,
PackOperation.writePackageJson,
PackOperation.writeEntryScript,
PackOperation.copyMonoRepoResources,
PackOperation.copyResources,
PackOperation.writeManifest,
PackOperation.bundle,
];
}
/**
* Run all operations
*/
async * runOperations(): AsyncIterable<string> {
for (const op of this.getOperations()) {
for await (const msg of op(this)) {
yield msg.join(' ');
}
}
}
/**
* Get all binary dependencies
*/
getBinaryDependencies(): string[] {
return [...RuntimeIndex.getModuleList('all')]
.map(m => RuntimeIndex.getModule(m))
.filter(m => !!m)
.filter(m => m.prod)
.map(m => PackageUtil.readPackage(m?.sourcePath))
.map(p => p?.travetto?.build?.binaryDependencies ?? [])
.flat();
}
async main(args: string[] = []): Promise<void> {
// Resolve all files to absolute paths
this.output = this.output ? path.resolve(this.output) : undefined!;
this.ejectFile = this.ejectFile ? path.resolve(this.ejectFile) : undefined;
this.buildDir = path.resolve(this.buildDir);
// Update entry points
this.entryArguments = [...this.entryArguments ?? [], ...args, ...this._parsed.unknown];
this.module ||= Runtime.main.name;
this.mainName ??= path.basename(this.module);
this.mainFile = `${this.mainName}.js`;
// Collect binary dependencies
const binaryDeps = await this.getBinaryDependencies();
this.externalDependencies = [...this.externalDependencies, ...binaryDeps];
const stream = this.runOperations();
// Eject to file
if (this.ejectFile) {
await PackUtil.writeEjectOutput(this.buildDir, this.module, stream, this.ejectFile);
} else {
const start = Date.now();
const term = new Terminal();
await term.streamLines(stream);
let msg = cliTpl`${{ success: 'Success' }} (${{ identifier: TimeUtil.asClock(Date.now() - start) }}) ${{ subtitle: 'module' }}=${{ param: this.module }}`;
if (this.output) {
msg = cliTpl`${msg} ${{ subtitle: 'output' }}=${{ path: this.output }}`;
}
await term.writer.writeLine(msg).commit();
}
}
}