feat(cli): add npmextra-based compile target configuration for deno builds
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@git.zone/tsdeno',
|
||||
version: '1.0.1',
|
||||
version: '1.1.0',
|
||||
description: 'A helper tool for deno compile that strips package.json to prevent devDependency bloat in compiled binaries.'
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import * as early from '@push.rocks/early';
|
||||
early.start('tsdeno');
|
||||
|
||||
export * from './tsdeno.classes.tsdeno.js';
|
||||
export * from './tsdeno.interfaces.js';
|
||||
export { runCli } from './tsdeno.cli.js';
|
||||
|
||||
early.stop();
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
// node native
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
export { path, fs };
|
||||
export { path };
|
||||
|
||||
// @push.rocks scope
|
||||
import * as npmextra from '@push.rocks/npmextra';
|
||||
import * as smartcli from '@push.rocks/smartcli';
|
||||
import * as smartfile from '@push.rocks/smartfile';
|
||||
import * as smartlog from '@push.rocks/smartlog';
|
||||
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
|
||||
import * as smartpath from '@push.rocks/smartpath';
|
||||
import { SmartFs, SmartFsProviderNode } from '@push.rocks/smartfs';
|
||||
import * as smartshell from '@push.rocks/smartshell';
|
||||
|
||||
export {
|
||||
npmextra,
|
||||
smartcli,
|
||||
smartfile,
|
||||
smartlog,
|
||||
smartlogDestinationLocal,
|
||||
smartpath,
|
||||
SmartFs,
|
||||
SmartFsProviderNode,
|
||||
smartshell,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import * as plugins from './plugins.js';
|
||||
import type { ITsdenoConfig, ICompileTarget } from './tsdeno.interfaces.js';
|
||||
|
||||
const shell = new plugins.smartshell.Smartshell({
|
||||
executor: 'bash',
|
||||
});
|
||||
|
||||
const smartfs = new plugins.SmartFs(new plugins.SmartFsProviderNode());
|
||||
|
||||
export class TsDeno {
|
||||
public cwd: string;
|
||||
|
||||
@@ -20,13 +23,7 @@ export class TsDeno {
|
||||
const packageJsonPath = plugins.path.join(this.cwd, 'package.json');
|
||||
const backupPath = plugins.path.join(this.cwd, 'package.json.bak');
|
||||
|
||||
let hasPackageJson = false;
|
||||
try {
|
||||
await plugins.fs.access(packageJsonPath);
|
||||
hasPackageJson = true;
|
||||
} catch {
|
||||
hasPackageJson = false;
|
||||
}
|
||||
const hasPackageJson = await smartfs.file(packageJsonPath).exists();
|
||||
|
||||
// Ensure --node-modules-dir=none is present
|
||||
if (!args.some((arg) => arg.startsWith('--node-modules-dir'))) {
|
||||
@@ -36,7 +33,7 @@ export class TsDeno {
|
||||
// Temporarily hide package.json from Deno
|
||||
if (hasPackageJson) {
|
||||
console.log('tsdeno: temporarily hiding package.json to exclude devDependencies from bundle');
|
||||
await plugins.fs.rename(packageJsonPath, backupPath);
|
||||
await smartfs.file(packageJsonPath).move(backupPath);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -51,9 +48,81 @@ export class TsDeno {
|
||||
} finally {
|
||||
// Always restore package.json
|
||||
if (hasPackageJson) {
|
||||
await plugins.fs.rename(backupPath, packageJsonPath);
|
||||
await smartfs.file(backupPath).move(packageJsonPath);
|
||||
console.log('tsdeno: restored package.json');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads compile targets from npmextra.json and compiles each one.
|
||||
* The package.json hide/restore wraps the entire loop.
|
||||
*/
|
||||
public async compileFromConfig(): Promise<void> {
|
||||
const npmextraInstance = new plugins.npmextra.Npmextra(this.cwd);
|
||||
const config = npmextraInstance.dataFor<ITsdenoConfig>('@git.zone/tsdeno', {
|
||||
compileTargets: [],
|
||||
});
|
||||
|
||||
if (config.compileTargets.length === 0) {
|
||||
console.error('tsdeno: no compileTargets found in npmextra.json under "@git.zone/tsdeno"');
|
||||
console.error('tsdeno: either pass args directly or add config to npmextra.json');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`tsdeno: found ${config.compileTargets.length} compile target(s) in npmextra.json`);
|
||||
|
||||
const packageJsonPath = plugins.path.join(this.cwd, 'package.json');
|
||||
const backupPath = plugins.path.join(this.cwd, 'package.json.bak');
|
||||
const hasPackageJson = await smartfs.file(packageJsonPath).exists();
|
||||
|
||||
// Hide package.json once for all targets
|
||||
if (hasPackageJson) {
|
||||
console.log('tsdeno: temporarily hiding package.json to exclude devDependencies from bundle');
|
||||
await smartfs.file(packageJsonPath).move(backupPath);
|
||||
}
|
||||
|
||||
try {
|
||||
for (const target of config.compileTargets) {
|
||||
console.log(`\ntsdeno: compiling target "${target.name}"...`);
|
||||
const args = this.buildArgsFromTarget(target);
|
||||
const shellCommand = `cd ${this.cwd} && deno compile ${args.join(' ')}`;
|
||||
console.log(`tsdeno: running deno compile ${args.join(' ')}`);
|
||||
const result = await shell.execPassthrough(shellCommand);
|
||||
|
||||
if (result.exitCode !== 0) {
|
||||
console.error(`tsdeno: deno compile exited with code ${result.exitCode} for target "${target.name}"`);
|
||||
process.exit(result.exitCode);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (hasPackageJson) {
|
||||
await smartfs.file(backupPath).move(packageJsonPath);
|
||||
console.log('\ntsdeno: restored package.json');
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\ntsdeno: all ${config.compileTargets.length} target(s) compiled successfully`);
|
||||
}
|
||||
|
||||
private buildArgsFromTarget(target: ICompileTarget): string[] {
|
||||
const args: string[] = ['--node-modules-dir=none'];
|
||||
|
||||
if (target.noCheck) {
|
||||
args.push('--no-check');
|
||||
}
|
||||
|
||||
if (target.permissions) {
|
||||
args.push(...target.permissions);
|
||||
}
|
||||
|
||||
const outputPath = plugins.path.join(target.outDir, target.name);
|
||||
args.push('--output', outputPath);
|
||||
|
||||
args.push('--target', target.target);
|
||||
|
||||
args.push(target.entryPoint);
|
||||
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@ tsdenoCli.standardCommand().subscribe(async (argvArg) => {
|
||||
console.log(`@git.zone/tsdeno v${commitinfo.version}`);
|
||||
console.log('');
|
||||
console.log('Usage:');
|
||||
console.log(' tsdeno compile [deno compile args...] Compile with package.json isolation');
|
||||
console.log(' tsdeno compile Compile all targets from npmextra.json');
|
||||
console.log(' tsdeno compile [deno compile args...] Compile with explicit args (passthrough)');
|
||||
console.log('');
|
||||
console.log('When no args are given, tsdeno reads compileTargets from npmextra.json.');
|
||||
console.log('The compile command temporarily removes package.json before running');
|
||||
console.log('deno compile, preventing devDependencies from bloating the binary.');
|
||||
console.log('--node-modules-dir=none is added automatically.');
|
||||
@@ -19,11 +21,15 @@ tsdenoCli.standardCommand().subscribe(async (argvArg) => {
|
||||
|
||||
tsdenoCli.addCommand('compile').subscribe(async (argvArg) => {
|
||||
const tsDeno = new TsDeno();
|
||||
|
||||
// Pass through all args after "compile" to deno compile
|
||||
const rawArgs = process.argv.slice(3);
|
||||
|
||||
await tsDeno.compile(rawArgs);
|
||||
if (rawArgs.length === 0) {
|
||||
// No args — read targets from npmextra.json
|
||||
await tsDeno.compileFromConfig();
|
||||
} else {
|
||||
// Args provided — passthrough to deno compile
|
||||
await tsDeno.compile(rawArgs);
|
||||
}
|
||||
});
|
||||
|
||||
export { tsdenoCli };
|
||||
|
||||
12
ts/tsdeno.interfaces.ts
Normal file
12
ts/tsdeno.interfaces.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export interface ITsdenoConfig {
|
||||
compileTargets: ICompileTarget[];
|
||||
}
|
||||
|
||||
export interface ICompileTarget {
|
||||
name: string;
|
||||
entryPoint: string;
|
||||
outDir: string;
|
||||
target: string;
|
||||
permissions?: string[];
|
||||
noCheck?: boolean;
|
||||
}
|
||||
Reference in New Issue
Block a user