Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 801cab9001 | |||
| 971cb685a7 | |||
| 0900d1a605 | |||
| f0fb99c8ae | |||
| 6d88adcd1e | |||
| 4349571112 | |||
| b3080023ab | |||
| 8b6ae043a2 | |||
| 54f84ba114 | |||
| e40d6477fd |
36
changelog.md
36
changelog.md
@@ -1,5 +1,41 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-01-23 - 2.8.3 - fix(mod_output)
|
||||
use pattern base dir when computing relative paths for files to serve
|
||||
|
||||
- Compute relativePath using the pattern base directory (dirPath) instead of this.cwd to ensure correct web-serving paths for absolute or relative entry.path values.
|
||||
- File changed: ts/mod_output/index.ts — replaces plugins.path.relative(this.cwd, fullPath) with plugins.path.relative(dirPath, fullPath) and adds clarifying comment.
|
||||
|
||||
## 2026-01-23 - 2.8.2 - fix(mod_output)
|
||||
resolve absolute and relative entry.path correctly when adding files
|
||||
|
||||
- Add check for plugins.path.isAbsolute(entry.path) to avoid incorrectly joining absolute paths with dirPath
|
||||
- Use entry.path directly when it's absolute, otherwise join with dirPath
|
||||
- Ensures correct relativePath calculation and prevents invalid file reads
|
||||
|
||||
## 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)
|
||||
wrap long base64 file contents and format generated TypeScript output to avoid extremely long lines
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@git.zone/tsbundle",
|
||||
"version": "2.7.3",
|
||||
"version": "2.8.3",
|
||||
"private": false,
|
||||
"description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects",
|
||||
"main": "dist_ts/index.js",
|
||||
@@ -25,10 +25,10 @@
|
||||
"dependencies": {
|
||||
"@push.rocks/early": "^4.0.4",
|
||||
"@push.rocks/npmextra": "^5.1.3",
|
||||
"@push.rocks/smartcli": "^4.0.19",
|
||||
"@push.rocks/smartinteract": "^2.0.16",
|
||||
"@push.rocks/smartcli": "^4.0.20",
|
||||
"@push.rocks/smartdelay": "^3.0.5",
|
||||
"@push.rocks/smartfs": "^1.1.3",
|
||||
"@push.rocks/smartinteract": "^2.0.16",
|
||||
"@push.rocks/smartlog": "^3.1.8",
|
||||
"@push.rocks/smartlog-destination-local": "^9.0.2",
|
||||
"@push.rocks/smartpath": "^6.0.0",
|
||||
|
||||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
@@ -15,8 +15,8 @@ importers:
|
||||
specifier: ^5.1.3
|
||||
version: 5.3.3
|
||||
'@push.rocks/smartcli':
|
||||
specifier: ^4.0.19
|
||||
version: 4.0.19
|
||||
specifier: ^4.0.20
|
||||
version: 4.0.20
|
||||
'@push.rocks/smartdelay':
|
||||
specifier: ^3.0.5
|
||||
version: 3.0.5
|
||||
@@ -913,8 +913,8 @@ packages:
|
||||
'@push.rocks/smartchok@1.1.1':
|
||||
resolution: {integrity: sha512-WmNigGmn1muBJMANVuJb4F8x3TzgYrnn6YZm6ixTsG+0WFbYevivEwp+J4S7npobLHsR7ynf+Ky8LxRYmsL50A==}
|
||||
|
||||
'@push.rocks/smartcli@4.0.19':
|
||||
resolution: {integrity: sha512-s1jZSgDZWi/az26AY4TJ2HPuG1qZzGC5R9fKWaECLmwnSpk6y9JXL5dnJAUohcdu50kdXCWEcRmLfYxOt81vEA==}
|
||||
'@push.rocks/smartcli@4.0.20':
|
||||
resolution: {integrity: sha512-gCo4ItvsPj8WoVAJw/6vkuoGA5FtIoACux2ktcCeH0nrFe7/xGR6waJ1aZcYAi7QN4gi52TlsgwuKz7BzXqhmQ==}
|
||||
|
||||
'@push.rocks/smartclickhouse@2.0.17':
|
||||
resolution: {integrity: sha512-IYO8Obor/Ruam2KQ2B/+5uQ+rL0exU5KZoSgOc3jkkrfjn+zZenN2xoV8lVqavAtxZVfG7MfxFrcv6I7I9ZMmA==}
|
||||
@@ -4853,7 +4853,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@git.zone/tspublish': 1.10.3
|
||||
'@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/smartfile': 11.2.7
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
@@ -4872,7 +4872,7 @@ snapshots:
|
||||
'@git.zone/tsbundle@2.5.2':
|
||||
dependencies:
|
||||
'@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/smartfile': 11.2.7
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
@@ -4893,7 +4893,7 @@ snapshots:
|
||||
'@git.zone/tspublish@1.10.3':
|
||||
dependencies:
|
||||
'@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/smartfile': 11.2.7
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
@@ -5428,7 +5428,7 @@ snapshots:
|
||||
chokidar: 4.0.3
|
||||
picomatch: 4.0.3
|
||||
|
||||
'@push.rocks/smartcli@4.0.19':
|
||||
'@push.rocks/smartcli@4.0.20':
|
||||
dependencies:
|
||||
'@push.rocks/lik': 6.2.2
|
||||
'@push.rocks/smartlog': 3.1.10
|
||||
|
||||
@@ -91,6 +91,7 @@ tsbundle uses `npmextra.json` for configuration. Here's an example:
|
||||
| `bundler` | `"esbuild"` \| `"rolldown"` \| `"rspack"` | `"esbuild"` | Which bundler to use |
|
||||
| `production` | `boolean` | `false` | Enable minification |
|
||||
| `includeFiles` | `string[]` | `[]` | Glob patterns for additional files (HTML, assets) |
|
||||
| `maxLineLength` | `number` | `0` (unlimited) | For `base64ts` mode: max chars per line in output |
|
||||
|
||||
### 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 🔧
|
||||
|
||||
tsbundle supports three modern bundlers:
|
||||
@@ -241,7 +244,8 @@ Config:
|
||||
"outputMode": "base64ts",
|
||||
"bundler": "esbuild",
|
||||
"production": true,
|
||||
"includeFiles": ["./html/index.html"]
|
||||
"includeFiles": ["./html/index.html"],
|
||||
"maxLineLength": 200
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@git.zone/tsbundle',
|
||||
version: '2.7.3',
|
||||
version: '2.8.3',
|
||||
description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects'
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ export interface IBundleConfig {
|
||||
bundler?: TBundler;
|
||||
production?: boolean;
|
||||
includeFiles?: string[];
|
||||
maxLineLength?: number; // For base64ts output: max chars per line. 0 or undefined = unlimited (default)
|
||||
}
|
||||
|
||||
export interface ITsbundleConfig {
|
||||
|
||||
@@ -61,6 +61,7 @@ export class CustomBundleHandler {
|
||||
|
||||
// Build the bundle to temp location
|
||||
const tsbundle = new TsBundle();
|
||||
try {
|
||||
await tsbundle.build(
|
||||
this.cwd,
|
||||
bundleConfig.from,
|
||||
@@ -70,6 +71,11 @@ export class CustomBundleHandler {
|
||||
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') {
|
||||
await this.handleBase64TsOutput(bundleConfig, tempBundlePath);
|
||||
@@ -105,7 +111,7 @@ export class CustomBundleHandler {
|
||||
}
|
||||
|
||||
// Write the TypeScript output
|
||||
await base64Output.writeToFile(bundleConfig.to);
|
||||
await base64Output.writeToFile(bundleConfig.to, bundleConfig.maxLineLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,6 +79,7 @@ export class TsBundleProcess {
|
||||
}
|
||||
|
||||
const run = async () => {
|
||||
try {
|
||||
console.log('running spawned compilation process');
|
||||
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
||||
process.env.transportOptions,
|
||||
@@ -90,7 +91,7 @@ const run = async () => {
|
||||
const tsbundleProcessInstance = new TsBundleProcess();
|
||||
if (transportOptions.mode === 'test') {
|
||||
console.log('building for test:');
|
||||
tsbundleProcessInstance.buildTest(
|
||||
await tsbundleProcessInstance.buildTest(
|
||||
plugins.smartpath.transform.makeAbsolute(
|
||||
transportOptions.from,
|
||||
process.cwd(),
|
||||
@@ -103,7 +104,7 @@ const run = async () => {
|
||||
);
|
||||
} else {
|
||||
console.log('building for production:');
|
||||
tsbundleProcessInstance.buildProduction(
|
||||
await tsbundleProcessInstance.buildProduction(
|
||||
plugins.smartpath.transform.makeAbsolute(
|
||||
transportOptions.from,
|
||||
process.cwd(),
|
||||
@@ -115,6 +116,29 @@ const run = async () => {
|
||||
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();
|
||||
|
||||
@@ -56,8 +56,12 @@ export class Base64TsOutput {
|
||||
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory && regex.test(entry.name)) {
|
||||
const fullPath = plugins.path.join(dirPath, entry.path);
|
||||
const relativePath = plugins.path.relative(this.cwd, fullPath);
|
||||
// entry.path may be absolute or relative - handle both cases
|
||||
const fullPath = plugins.path.isAbsolute(entry.path)
|
||||
? entry.path
|
||||
: plugins.path.join(dirPath, entry.path);
|
||||
// Use path relative to pattern's base dir (not cwd) for web serving
|
||||
const relativePath = plugins.path.relative(dirPath, fullPath);
|
||||
const content = await plugins.fs.file(fullPath).read();
|
||||
this.addFile(relativePath, content);
|
||||
}
|
||||
@@ -77,18 +81,26 @@ export class Base64TsOutput {
|
||||
|
||||
/**
|
||||
* Generate TypeScript file content
|
||||
* @param maxLineLength - Max chars per line for base64 strings. 0 or undefined = unlimited (default)
|
||||
*/
|
||||
public generateTypeScript(): string {
|
||||
const MAX_LINE_LENGTH = 200;
|
||||
public generateTypeScript(maxLineLength?: number): string {
|
||||
// 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 => {
|
||||
if (base64.length <= MAX_LINE_LENGTH) {
|
||||
if (base64.length <= maxLineLength) {
|
||||
return `"${base64}"`;
|
||||
}
|
||||
|
||||
const chunks: string[] = [];
|
||||
for (let i = 0; i < base64.length; i += MAX_LINE_LENGTH) {
|
||||
chunks.push(base64.slice(i, i + MAX_LINE_LENGTH));
|
||||
for (let i = 0; i < base64.length; i += maxLineLength) {
|
||||
chunks.push(base64.slice(i, i + maxLineLength));
|
||||
}
|
||||
|
||||
return `"" +\n "${chunks.join('" +\n "')}"`;
|
||||
@@ -110,12 +122,14 @@ ${filesFormatted}
|
||||
|
||||
/**
|
||||
* 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 outputDir = plugins.path.dirname(absolutePath);
|
||||
await plugins.fs.directory(outputDir).create();
|
||||
const content = this.generateTypeScript();
|
||||
const content = this.generateTypeScript(maxLineLength);
|
||||
await plugins.fs.file(absolutePath).encoding('utf8').write(content);
|
||||
console.log(`Generated base64ts output: ${outputPath}`);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,11 @@ export class TsBundle {
|
||||
);
|
||||
const childProcess = await threadsimple.start();
|
||||
childProcess.on('exit', (status) => {
|
||||
if (status !== 0) {
|
||||
done.reject(new Error(`Bundle build failed with exit code ${status}`));
|
||||
} else {
|
||||
done.resolve();
|
||||
}
|
||||
});
|
||||
await done.promise;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user