Compare commits

..

4 Commits

Author SHA1 Message Date
b3080023ab v2.8.0
Some checks failed
Default (tags) / security (push) Successful in 34s
Default (tags) / test (push) Failing after 1m10s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-01-12 01:41:08 +00:00
8b6ae043a2 feat(tsbundle): add configurable maxLineLength for base64ts output and improve build/error handling in child builds 2026-01-12 01:41:08 +00:00
54f84ba114 v2.7.4
Some checks failed
Default (tags) / security (push) Successful in 38s
Default (tags) / test (push) Failing after 1m9s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-01-12 01:25:24 +00:00
e40d6477fd fix(deps): bump @push.rocks/smartcli dependency to ^4.0.20 2026-01-12 01:25:24 +00:00
9 changed files with 125 additions and 64 deletions

View File

@@ -1,5 +1,21 @@
# Changelog # Changelog
## 2026-01-12 - 2.8.0 - feat(tsbundle)
add configurable maxLineLength for base64ts output and improve build/error handling in child builds
- Add optional maxLineLength?: number to IBundleConfig to control max characters per line for base64ts output (0 or undefined = unlimited).
- Support splitting base64 strings when maxLineLength is specified; generateTypeScript(maxLineLength?) and writeToFile(outputPath, maxLineLength?) updated to accept and apply this setting.
- Pass bundleConfig.maxLineLength through in mod_custom so base64ts output respects bundle configuration.
- Wrap TsBundle.build in mod_custom with try/catch to log failures and skip output handling when build fails.
- tsbundle.class now rejects the bundle promise when the child process exits with a non-zero status.
- mod_esbuild child process now awaits builds, exits with appropriate success/failure codes, and formats esbuild errors for clearer console output.
## 2026-01-12 - 2.7.4 - fix(deps)
bump @push.rocks/smartcli dependency to ^4.0.20
- @push.rocks/smartcli: ^4.0.19 → ^4.0.20
- Patch-level dependency update with no breaking changes
## 2026-01-12 - 2.7.3 - fix(mod_output) ## 2026-01-12 - 2.7.3 - fix(mod_output)
wrap long base64 file contents and format generated TypeScript output to avoid extremely long lines wrap long base64 file contents and format generated TypeScript output to avoid extremely long lines

View File

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tsbundle", "name": "@git.zone/tsbundle",
"version": "2.7.3", "version": "2.8.0",
"private": false, "private": false,
"description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects", "description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",
@@ -25,10 +25,10 @@
"dependencies": { "dependencies": {
"@push.rocks/early": "^4.0.4", "@push.rocks/early": "^4.0.4",
"@push.rocks/npmextra": "^5.1.3", "@push.rocks/npmextra": "^5.1.3",
"@push.rocks/smartcli": "^4.0.19", "@push.rocks/smartcli": "^4.0.20",
"@push.rocks/smartinteract": "^2.0.16",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfs": "^1.1.3", "@push.rocks/smartfs": "^1.1.3",
"@push.rocks/smartinteract": "^2.0.16",
"@push.rocks/smartlog": "^3.1.8", "@push.rocks/smartlog": "^3.1.8",
"@push.rocks/smartlog-destination-local": "^9.0.2", "@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartpath": "^6.0.0", "@push.rocks/smartpath": "^6.0.0",

16
pnpm-lock.yaml generated
View File

@@ -15,8 +15,8 @@ importers:
specifier: ^5.1.3 specifier: ^5.1.3
version: 5.3.3 version: 5.3.3
'@push.rocks/smartcli': '@push.rocks/smartcli':
specifier: ^4.0.19 specifier: ^4.0.20
version: 4.0.19 version: 4.0.20
'@push.rocks/smartdelay': '@push.rocks/smartdelay':
specifier: ^3.0.5 specifier: ^3.0.5
version: 3.0.5 version: 3.0.5
@@ -913,8 +913,8 @@ packages:
'@push.rocks/smartchok@1.1.1': '@push.rocks/smartchok@1.1.1':
resolution: {integrity: sha512-WmNigGmn1muBJMANVuJb4F8x3TzgYrnn6YZm6ixTsG+0WFbYevivEwp+J4S7npobLHsR7ynf+Ky8LxRYmsL50A==} resolution: {integrity: sha512-WmNigGmn1muBJMANVuJb4F8x3TzgYrnn6YZm6ixTsG+0WFbYevivEwp+J4S7npobLHsR7ynf+Ky8LxRYmsL50A==}
'@push.rocks/smartcli@4.0.19': '@push.rocks/smartcli@4.0.20':
resolution: {integrity: sha512-s1jZSgDZWi/az26AY4TJ2HPuG1qZzGC5R9fKWaECLmwnSpk6y9JXL5dnJAUohcdu50kdXCWEcRmLfYxOt81vEA==} resolution: {integrity: sha512-gCo4ItvsPj8WoVAJw/6vkuoGA5FtIoACux2ktcCeH0nrFe7/xGR6waJ1aZcYAi7QN4gi52TlsgwuKz7BzXqhmQ==}
'@push.rocks/smartclickhouse@2.0.17': '@push.rocks/smartclickhouse@2.0.17':
resolution: {integrity: sha512-IYO8Obor/Ruam2KQ2B/+5uQ+rL0exU5KZoSgOc3jkkrfjn+zZenN2xoV8lVqavAtxZVfG7MfxFrcv6I7I9ZMmA==} resolution: {integrity: sha512-IYO8Obor/Ruam2KQ2B/+5uQ+rL0exU5KZoSgOc3jkkrfjn+zZenN2xoV8lVqavAtxZVfG7MfxFrcv6I7I9ZMmA==}
@@ -4853,7 +4853,7 @@ snapshots:
dependencies: dependencies:
'@git.zone/tspublish': 1.10.3 '@git.zone/tspublish': 1.10.3
'@push.rocks/early': 4.0.4 '@push.rocks/early': 4.0.4
'@push.rocks/smartcli': 4.0.19 '@push.rocks/smartcli': 4.0.20
'@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartfile': 11.2.7 '@push.rocks/smartfile': 11.2.7
'@push.rocks/smartlog': 3.1.10 '@push.rocks/smartlog': 3.1.10
@@ -4872,7 +4872,7 @@ snapshots:
'@git.zone/tsbundle@2.5.2': '@git.zone/tsbundle@2.5.2':
dependencies: dependencies:
'@push.rocks/early': 4.0.4 '@push.rocks/early': 4.0.4
'@push.rocks/smartcli': 4.0.19 '@push.rocks/smartcli': 4.0.20
'@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartfile': 11.2.7 '@push.rocks/smartfile': 11.2.7
'@push.rocks/smartlog': 3.1.10 '@push.rocks/smartlog': 3.1.10
@@ -4893,7 +4893,7 @@ snapshots:
'@git.zone/tspublish@1.10.3': '@git.zone/tspublish@1.10.3':
dependencies: dependencies:
'@push.rocks/consolecolor': 2.0.3 '@push.rocks/consolecolor': 2.0.3
'@push.rocks/smartcli': 4.0.19 '@push.rocks/smartcli': 4.0.20
'@push.rocks/smartdelay': 3.0.5 '@push.rocks/smartdelay': 3.0.5
'@push.rocks/smartfile': 11.2.7 '@push.rocks/smartfile': 11.2.7
'@push.rocks/smartlog': 3.1.10 '@push.rocks/smartlog': 3.1.10
@@ -5428,7 +5428,7 @@ snapshots:
chokidar: 4.0.3 chokidar: 4.0.3
picomatch: 4.0.3 picomatch: 4.0.3
'@push.rocks/smartcli@4.0.19': '@push.rocks/smartcli@4.0.20':
dependencies: dependencies:
'@push.rocks/lik': 6.2.2 '@push.rocks/lik': 6.2.2
'@push.rocks/smartlog': 3.1.10 '@push.rocks/smartlog': 3.1.10

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/tsbundle', name: '@git.zone/tsbundle',
version: '2.7.3', version: '2.8.0',
description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects' description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects'
} }

View File

@@ -24,6 +24,7 @@ export interface IBundleConfig {
bundler?: TBundler; bundler?: TBundler;
production?: boolean; production?: boolean;
includeFiles?: string[]; includeFiles?: string[];
maxLineLength?: number; // For base64ts output: max chars per line. 0 or undefined = unlimited (default)
} }
export interface ITsbundleConfig { export interface ITsbundleConfig {

View File

@@ -61,6 +61,7 @@ export class CustomBundleHandler {
// Build the bundle to temp location // Build the bundle to temp location
const tsbundle = new TsBundle(); const tsbundle = new TsBundle();
try {
await tsbundle.build( await tsbundle.build(
this.cwd, this.cwd,
bundleConfig.from, bundleConfig.from,
@@ -70,6 +71,11 @@ export class CustomBundleHandler {
production: bundleConfig.production || false, production: bundleConfig.production || false,
} }
); );
} catch (error: any) {
console.error(`\n\x1b[31m❌ Bundle failed: ${bundleConfig.from} -> ${bundleConfig.to}\x1b[0m`);
// Don't re-print error details - they were already shown by the child process
return; // Skip output handling since build failed
}
if (outputMode === 'base64ts') { if (outputMode === 'base64ts') {
await this.handleBase64TsOutput(bundleConfig, tempBundlePath); await this.handleBase64TsOutput(bundleConfig, tempBundlePath);
@@ -105,7 +111,7 @@ export class CustomBundleHandler {
} }
// Write the TypeScript output // Write the TypeScript output
await base64Output.writeToFile(bundleConfig.to); await base64Output.writeToFile(bundleConfig.to, bundleConfig.maxLineLength);
} }
/** /**

View File

@@ -79,6 +79,7 @@ export class TsBundleProcess {
} }
const run = async () => { const run = async () => {
try {
console.log('running spawned compilation process'); console.log('running spawned compilation process');
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse( const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
process.env.transportOptions, process.env.transportOptions,
@@ -90,7 +91,7 @@ const run = async () => {
const tsbundleProcessInstance = new TsBundleProcess(); const tsbundleProcessInstance = new TsBundleProcess();
if (transportOptions.mode === 'test') { if (transportOptions.mode === 'test') {
console.log('building for test:'); console.log('building for test:');
tsbundleProcessInstance.buildTest( await tsbundleProcessInstance.buildTest(
plugins.smartpath.transform.makeAbsolute( plugins.smartpath.transform.makeAbsolute(
transportOptions.from, transportOptions.from,
process.cwd(), process.cwd(),
@@ -103,7 +104,7 @@ const run = async () => {
); );
} else { } else {
console.log('building for production:'); console.log('building for production:');
tsbundleProcessInstance.buildProduction( await tsbundleProcessInstance.buildProduction(
plugins.smartpath.transform.makeAbsolute( plugins.smartpath.transform.makeAbsolute(
transportOptions.from, transportOptions.from,
process.cwd(), process.cwd(),
@@ -115,6 +116,29 @@ const run = async () => {
transportOptions.argv, transportOptions.argv,
); );
} }
process.exit(0);
} catch (error: any) {
console.error('\n\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m');
console.error('\x1b[31m❌ BUILD FAILED\x1b[0m');
console.error('\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n');
if (error.errors && Array.isArray(error.errors)) {
// esbuild errors - format them nicely
console.error(`Found ${error.errors.length} error(s):\n`);
for (const err of error.errors) {
const file = err.location?.file || 'unknown';
const line = err.location?.line || '?';
const column = err.location?.column || '?';
console.error(` \x1b[36m${file}\x1b[0m:\x1b[33m${line}\x1b[0m:\x1b[33m${column}\x1b[0m`);
console.error(` ${err.text}\n`);
}
} else {
console.error(error.message || error);
}
console.error('\x1b[31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\x1b[0m\n');
process.exit(1);
}
}; };
run(); run();

View File

@@ -77,18 +77,26 @@ export class Base64TsOutput {
/** /**
* Generate TypeScript file content * Generate TypeScript file content
* @param maxLineLength - Max chars per line for base64 strings. 0 or undefined = unlimited (default)
*/ */
public generateTypeScript(): string { public generateTypeScript(maxLineLength?: number): string {
const MAX_LINE_LENGTH = 200; // Default behavior: no line splitting (unlimited)
if (!maxLineLength || maxLineLength <= 0) {
const filesJson = JSON.stringify(this.files, null, 2);
return `// Auto-generated by tsbundle - do not edit
export const files: { path: string; contentBase64: string }[] = ${filesJson};
`;
}
// Split base64 strings into chunks when maxLineLength is specified
const formatBase64 = (base64: string): string => { const formatBase64 = (base64: string): string => {
if (base64.length <= MAX_LINE_LENGTH) { if (base64.length <= maxLineLength) {
return `"${base64}"`; return `"${base64}"`;
} }
const chunks: string[] = []; const chunks: string[] = [];
for (let i = 0; i < base64.length; i += MAX_LINE_LENGTH) { for (let i = 0; i < base64.length; i += maxLineLength) {
chunks.push(base64.slice(i, i + MAX_LINE_LENGTH)); chunks.push(base64.slice(i, i + maxLineLength));
} }
return `"" +\n "${chunks.join('" +\n "')}"`; return `"" +\n "${chunks.join('" +\n "')}"`;
@@ -110,12 +118,14 @@ ${filesFormatted}
/** /**
* Write the TypeScript file to disk * Write the TypeScript file to disk
* @param outputPath - Output file path
* @param maxLineLength - Max chars per line for base64 strings. 0 or undefined = unlimited (default)
*/ */
public async writeToFile(outputPath: string): Promise<void> { public async writeToFile(outputPath: string, maxLineLength?: number): Promise<void> {
const absolutePath = plugins.smartpath.transform.toAbsolute(outputPath, this.cwd) as string; const absolutePath = plugins.smartpath.transform.toAbsolute(outputPath, this.cwd) as string;
const outputDir = plugins.path.dirname(absolutePath); const outputDir = plugins.path.dirname(absolutePath);
await plugins.fs.directory(outputDir).create(); await plugins.fs.directory(outputDir).create();
const content = this.generateTypeScript(); const content = this.generateTypeScript(maxLineLength);
await plugins.fs.file(absolutePath).encoding('utf8').write(content); await plugins.fs.file(absolutePath).encoding('utf8').write(content);
console.log(`Generated base64ts output: ${outputPath}`); console.log(`Generated base64ts output: ${outputPath}`);
} }

View File

@@ -45,7 +45,11 @@ export class TsBundle {
); );
const childProcess = await threadsimple.start(); const childProcess = await threadsimple.start();
childProcess.on('exit', (status) => { childProcess.on('exit', (status) => {
if (status !== 0) {
done.reject(new Error(`Bundle build failed with exit code ${status}`));
} else {
done.resolve(); done.resolve();
}
}); });
await done.promise; await done.promise;
} }