refactor(stats): restructured embedded client archive
- Migrated embedded client archive from base64 constant to lazy-loaded text file for reduced bundle size.
- Refactored extractEmbeddedClientArchive() to accept archiveBytes parameter, decoupling archive loading from extraction logic.
- Optimized getLatestMtime() to use parallel Promise.allSettled() instead of sequential awaits for improved performance.
- Replaced Buffer.from().toString('base64') with btoa() for base64 encoding in clipboard module.
This commit is contained in:
@@ -27,7 +27,7 @@ const hasDisplay = process.platform !== "linux" || Boolean(process.env.DISPLAY |
|
||||
*/
|
||||
export async function copyToClipboard(text: string): Promise<void> {
|
||||
if (process.stdout.isTTY) {
|
||||
const encoded = Buffer.from(text).toString("base64");
|
||||
const encoded = btoa(text);
|
||||
const osc52 = `\x1b]52;c;${encoded}\x07`;
|
||||
const onError = (err: unknown) => {
|
||||
process.stdout.off("error", onError);
|
||||
|
||||
@@ -5,7 +5,7 @@ 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 GENERATED_FILE = path.join("src", "embedded-client.generated.txt");
|
||||
const DIST_CLIENT_DIR = path.join("dist", "client");
|
||||
|
||||
function placeholderContent(): string {
|
||||
@@ -55,17 +55,6 @@ async function buildArchiveBase64(dir: string): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -75,7 +64,7 @@ async function main(): Promise<void> {
|
||||
|
||||
await $`bun run build`;
|
||||
const archiveBase64 = await buildArchiveBase64(DIST_CLIENT_DIR);
|
||||
await writeGeneratedBundle(archiveBase64);
|
||||
await Bun.write(GENERATED_FILE, archiveBase64);
|
||||
console.log(`Generated ${GENERATED_FILE}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* 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 = "";
|
||||
@@ -10,7 +10,13 @@ import {
|
||||
getTotalMessageCount,
|
||||
syncAllSessions,
|
||||
} from "./aggregator";
|
||||
import { EMBEDDED_CLIENT_ARCHIVE_TAR_GZ_BASE64 } from "./embedded-client.generated";
|
||||
import embeddedClientArchiveTxt from "./embedded-client.generated.txt";
|
||||
|
||||
const getEmbeddedClientArchive = (() => {
|
||||
const txt = embeddedClientArchiveTxt.replaceAll(/[\s\r\n]/g, "").trim();
|
||||
if (!txt) return null;
|
||||
return () => Buffer.from(txt, "base64");
|
||||
})();
|
||||
|
||||
const CLIENT_DIR = path.join(import.meta.dir, "client");
|
||||
const STATIC_DIR = path.join(import.meta.dir, "..", "dist", "client");
|
||||
@@ -30,8 +36,7 @@ function sanitizeArchivePath(archivePath: string): string | null {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
async function extractEmbeddedClientArchive(outputDir: string): Promise<void> {
|
||||
const archiveBytes = Buffer.from(EMBEDDED_CLIENT_ARCHIVE_TAR_GZ_BASE64, "base64");
|
||||
async function extractEmbeddedClientArchive(archiveBytes: Buffer, outputDir: string): Promise<void> {
|
||||
const archive = new Bun.Archive(archiveBytes);
|
||||
const files = await archive.files();
|
||||
const extractRoot = path.resolve(outputDir);
|
||||
@@ -49,13 +54,15 @@ async function extractEmbeddedClientArchive(outputDir: string): Promise<void> {
|
||||
|
||||
async function getCompiledClientDir(): Promise<string> {
|
||||
if (!IS_BUN_COMPILED) return STATIC_DIR;
|
||||
if (!EMBEDDED_CLIENT_ARCHIVE_TAR_GZ_BASE64) {
|
||||
throw new Error("Compiled stats client bundle missing. Rebuild binary with embedded stats assets.");
|
||||
}
|
||||
if (compiledClientDirPromise) return compiledClientDirPromise;
|
||||
|
||||
const archiveBytes = getEmbeddedClientArchive?.();
|
||||
if (!archiveBytes) {
|
||||
throw new Error("Compiled stats client bundle missing. Rebuild binary with embedded stats assets.");
|
||||
}
|
||||
|
||||
compiledClientDirPromise = (async () => {
|
||||
const bundleHash = Bun.hash(EMBEDDED_CLIENT_ARCHIVE_TAR_GZ_BASE64).toString(16);
|
||||
const bundleHash = Bun.hash(archiveBytes).toString(16);
|
||||
const outputDir = path.join(COMPILED_CLIENT_DIR_ROOT, bundleHash);
|
||||
const markerPath = path.join(outputDir, "index.html");
|
||||
try {
|
||||
@@ -65,7 +72,7 @@ async function getCompiledClientDir(): Promise<string> {
|
||||
|
||||
await fs.rm(outputDir, { recursive: true, force: true });
|
||||
await fs.mkdir(outputDir, { recursive: true });
|
||||
await extractEmbeddedClientArchive(outputDir);
|
||||
await extractEmbeddedClientArchive(archiveBytes, outputDir);
|
||||
return outputDir;
|
||||
})();
|
||||
|
||||
@@ -73,19 +80,26 @@ async function getCompiledClientDir(): Promise<string> {
|
||||
}
|
||||
|
||||
async function getLatestMtime(dir: string): Promise<number> {
|
||||
let latest = 0;
|
||||
const entries = await fs.readdir(dir, { withFileTypes: true });
|
||||
|
||||
const promises = [];
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
latest = Math.max(latest, await getLatestMtime(fullPath));
|
||||
promises.push(getLatestMtime(fullPath));
|
||||
} else if (entry.isFile()) {
|
||||
const stats = await fs.stat(fullPath);
|
||||
latest = Math.max(latest, stats.mtimeMs);
|
||||
promises.push(fs.stat(fullPath).then(stats => stats.mtimeMs));
|
||||
}
|
||||
}
|
||||
|
||||
let latest = 0;
|
||||
await Promise.allSettled(promises).then(results => {
|
||||
for (const result of results) {
|
||||
if (result.status === "fulfilled") {
|
||||
latest = Math.max(latest, result.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
return latest;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user