35aa15ae94
Generate a tar.gz bundle from stats dist/client during binary builds, embed it into the compiled binary, and extract/serve it at runtime in compiled mode instead of reading //root/client directly. Updated CI and build:binary flow to generate/reset the embedded bundle around compilation. Fixes #61
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
#!/usr/bin/env bun
|
|
|
|
import { $ } from "bun";
|
|
import * as fs from "node:fs/promises";
|
|
import * as path from "node:path";
|
|
import * as os from "node:os";
|
|
|
|
const GENERATED_FILE = path.join("src", "embedded-client.generated.ts");
|
|
const DIST_CLIENT_DIR = path.join("dist", "client");
|
|
|
|
function placeholderContent(): string {
|
|
return `/**
|
|
* Embedded stats dashboard bundle for compiled binaries.
|
|
*
|
|
* This file is generated by \`bun --cwd=packages/stats scripts/generate-client-bundle.ts\` during
|
|
* binary builds. The checked-in value is intentionally empty.
|
|
*/
|
|
export const EMBEDDED_CLIENT_ARCHIVE_TAR_GZ_BASE64 = "";
|
|
`;
|
|
}
|
|
|
|
async function collectFiles(dir: string): Promise<string[]> {
|
|
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
const files: string[] = [];
|
|
for (const entry of entries) {
|
|
const fullPath = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
files.push(...(await collectFiles(fullPath)));
|
|
} else if (entry.isFile()) {
|
|
files.push(fullPath);
|
|
}
|
|
}
|
|
files.sort((a, b) => a.localeCompare(b));
|
|
return files;
|
|
}
|
|
|
|
async function buildArchiveBase64(dir: string): Promise<string> {
|
|
const files = await collectFiles(dir);
|
|
const entries: Record<string, Uint8Array> = {};
|
|
for (const filePath of files) {
|
|
const relativePath = path.relative(dir, filePath).split(path.sep).join("/");
|
|
entries[relativePath] = await fs.readFile(filePath);
|
|
}
|
|
|
|
const tempArchivePath = path.join(
|
|
os.tmpdir(),
|
|
`omp-stats-client-${Bun.hash(Date.now().toString() + Math.random().toString(16)).toString(16)}.tar.gz`,
|
|
);
|
|
try {
|
|
await Bun.Archive.write(tempArchivePath, entries, { compress: "gzip" });
|
|
const archiveBytes = await Bun.file(tempArchivePath).bytes();
|
|
return Buffer.from(archiveBytes).toString("base64");
|
|
} finally {
|
|
await fs.rm(tempArchivePath, { force: true });
|
|
}
|
|
}
|
|
|
|
async function writeGeneratedBundle(base64Bundle: string): Promise<void> {
|
|
const content = `/**
|
|
* Embedded stats dashboard bundle for compiled binaries.
|
|
*
|
|
* Generated by \`bun --cwd=packages/stats scripts/generate-client-bundle.ts\`.
|
|
*/
|
|
export const EMBEDDED_CLIENT_ARCHIVE_TAR_GZ_BASE64 = ${JSON.stringify(base64Bundle)};
|
|
`;
|
|
await Bun.write(GENERATED_FILE, content);
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
if (process.argv.includes("--reset")) {
|
|
await Bun.write(GENERATED_FILE, placeholderContent());
|
|
console.log(`Reset ${GENERATED_FILE}`);
|
|
return;
|
|
}
|
|
|
|
await $`bun run build`;
|
|
const archiveBase64 = await buildArchiveBase64(DIST_CLIENT_DIR);
|
|
await writeGeneratedBundle(archiveBase64);
|
|
console.log(`Generated ${GENERATED_FILE}`);
|
|
}
|
|
|
|
await main();
|