mirror of
https://github.com/HananoshikaYomaru/openfreebooks.git
synced 2026-11-12 20:45:52 +00:00
102 lines
2.7 KiB
TypeScript
102 lines
2.7 KiB
TypeScript
import { readdir, stat } from "node:fs/promises";
|
|
import { join, relative } from "node:path";
|
|
|
|
const OUTPUT_DIRS = [
|
|
{ label: "Zola (deploy)", path: "public" },
|
|
{ label: "Vite JS/CSS", path: "themes/openfreebooks/static/js" },
|
|
] as const;
|
|
|
|
const TOP_FILES = 15;
|
|
|
|
type FileEntry = { path: string; bytes: number };
|
|
|
|
async function collectFiles(
|
|
dir: string,
|
|
root: string,
|
|
entries: FileEntry[],
|
|
): Promise<void> {
|
|
let items;
|
|
try {
|
|
items = await readdir(dir, { withFileTypes: true });
|
|
} catch {
|
|
return;
|
|
}
|
|
|
|
for (const item of items) {
|
|
const fullPath = join(dir, item.name);
|
|
if (item.isDirectory()) {
|
|
await collectFiles(fullPath, root, entries);
|
|
continue;
|
|
}
|
|
if (!item.isFile()) continue;
|
|
|
|
const { size } = await stat(fullPath);
|
|
entries.push({ path: relative(root, fullPath), bytes: size });
|
|
}
|
|
}
|
|
|
|
function formatBytes(bytes: number): string {
|
|
if (bytes < 1024) return `${bytes} B`;
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
}
|
|
|
|
function padEnd(value: string, width: number): string {
|
|
return value.length >= width ? value : value + " ".repeat(width - value.length);
|
|
}
|
|
|
|
async function scanDir(label: string, root: string) {
|
|
const entries: FileEntry[] = [];
|
|
await collectFiles(root, root, entries);
|
|
|
|
if (entries.length === 0) {
|
|
console.log(`\n${label} (${root}/)`);
|
|
console.log(" (missing or empty — run `bun run build` first)\n");
|
|
return null;
|
|
}
|
|
|
|
const total = entries.reduce((sum, e) => sum + e.bytes, 0);
|
|
entries.sort((a, b) => b.bytes - a.bytes);
|
|
|
|
console.log(`\n${label} (${root}/)`);
|
|
console.log(` files: ${entries.length}`);
|
|
console.log(` total: ${formatBytes(total)} (${total.toLocaleString()} bytes)`);
|
|
|
|
const labelWidth = Math.min(
|
|
52,
|
|
Math.max(...entries.slice(0, TOP_FILES).map((e) => e.path.length), 4),
|
|
);
|
|
|
|
console.log(`\n largest files:`);
|
|
for (const entry of entries.slice(0, TOP_FILES)) {
|
|
console.log(
|
|
` ${padEnd(entry.path, labelWidth)} ${padEnd(formatBytes(entry.bytes), 10)} ${entry.bytes.toLocaleString()} B`,
|
|
);
|
|
}
|
|
|
|
return { label, root, total, fileCount: entries.length, entries };
|
|
}
|
|
|
|
async function main() {
|
|
const cwd = process.cwd();
|
|
console.log(`Output size scan — ${cwd}`);
|
|
|
|
const results = [];
|
|
for (const { label, path } of OUTPUT_DIRS) {
|
|
const result = await scanDir(label, join(cwd, path));
|
|
if (result) results.push(result);
|
|
}
|
|
|
|
if (results.length > 0) {
|
|
const grandTotal = results.reduce((sum, r) => sum + r.total, 0);
|
|
console.log("\n---");
|
|
console.log(
|
|
`Combined tracked output: ${formatBytes(grandTotal)} (${grandTotal.toLocaleString()} bytes)`,
|
|
);
|
|
}
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|