Compare commits

..

6 Commits
v2.7.3 ... main

Author SHA1 Message Date
6d88adcd1e v2.8.1
Some checks failed
Default (tags) / security (push) Successful in 40s
Default (tags) / test (push) Failing after 34s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-01-12 02:03:38 +00:00
4349571112 fix(readme): document maxLineLength option for base64ts output and add example and tip 2026-01-12 02:03:38 +00:00
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
10 changed files with 137 additions and 65 deletions

View File

@@ -1,5 +1,28 @@
# Changelog # Changelog
## 2026-01-12 - 2.8.1 - fix(readme)
document maxLineLength option for base64ts output and add example and tip
- Add documented `maxLineLength` configuration option (number, default 0 = unlimited) for `base64ts` output.
- Include example config showing `maxLineLength: 200`.
- Add a tip recommending setting `maxLineLength` to split long base64 strings when using AI tools with line-length limits.
## 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.1",
"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

@@ -91,6 +91,7 @@ tsbundle uses `npmextra.json` for configuration. Here's an example:
| `bundler` | `"esbuild"` \| `"rolldown"` \| `"rspack"` | `"esbuild"` | Which bundler to use | | `bundler` | `"esbuild"` \| `"rolldown"` \| `"rspack"` | `"esbuild"` | Which bundler to use |
| `production` | `boolean` | `false` | Enable minification | | `production` | `boolean` | `false` | Enable minification |
| `includeFiles` | `string[]` | `[]` | Glob patterns for additional files (HTML, assets) | | `includeFiles` | `string[]` | `[]` | Glob patterns for additional files (HTML, assets) |
| `maxLineLength` | `number` | `0` (unlimited) | For `base64ts` mode: max chars per line in output |
### Output Modes ### Output Modes
@@ -108,6 +109,8 @@ export const files: { path: string; contentBase64: string }[] = [
]; ];
``` ```
**Tip:** If you're working with AI tools that have line length limitations, set `maxLineLength` (e.g., `200`) to split long base64 strings across multiple lines.
## Available Bundlers 🔧 ## Available Bundlers 🔧
tsbundle supports three modern bundlers: tsbundle supports three modern bundlers:
@@ -241,7 +244,8 @@ Config:
"outputMode": "base64ts", "outputMode": "base64ts",
"bundler": "esbuild", "bundler": "esbuild",
"production": true, "production": true,
"includeFiles": ["./html/index.html"] "includeFiles": ["./html/index.html"],
"maxLineLength": 200
} }
] ]
} }

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.1',
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;
} }