@gomani/budget
v0.1.0
Published
Enforced, build-failing performance budgets as code, with a CLI gate. Usable on any project.
Maintainers
Readme
@gomani/budget
Enforced, build-failing performance budgets as code — with a CLI gate. Part of Gomani, but deliberately usable on any project.
Performance is a usability threshold on the African internet, not a polish task. This tool makes the budget the framework's responsibility instead of the developer's memory: declare per-route byte / JS / TTI limits, and the check fails (exits non-zero) when a route regresses — a CI gate that catches the dependency that quietly doubled a route's weight at merge time, not in production.
Zero external runtime dependencies. Sizes are compressed Brotli (quality 11) wire bytes — the
size a CDN actually serves — and binary (kb = 1024), matching size-limit / bundlesize.
Install
npm install --save-dev @gomani/budgetDeclare budgets
Any field may be omitted (unbudgeted). A default applies to every route; per-route entries override
it (route fields win).
// gomani.budget.json
{
"default": { "css": "20kb", "total": "90kb", "tti": "3s@MBN" },
"routes": {
"/": { "js": "10kb", "total": "70kb" },
"/dashboard": { "js": "40kb", "total": "140kb" },
},
}Also accepted: gomani.config.{json,js,mjs,cjs,ts}, and defineBudget() for a typed config module.
Provide a manifest
The analyzer reads a small, bundler-neutral route→assets manifest:
// dist/gomani-manifest.json
{
"version": 1,
"routes": {
"/": { "assets": ["index.js", "index.css", { "path": "hero.avif", "type": "other" }] },
},
}@gomani/build emits this automatically. For non-Gomani projects, adapters convert a bundler's
own stats:
import { fromViteManifest, fromWebpackStats } from '@gomani/budget';Check (the gate)
gomani budget check # native Gomani manifest in ./dist
gomani budget check --adapter vite --manifest dist/.vite/manifest.json
gomani budget check --adapter webpack --manifest stats.json Route JS CSS Other Total TTI~
─────────────────────────────────────────────────────────
✓ / 8 KB 6 KB 12 KB 26 KB ~1.6s
✗ /dashboard 52 KB* 6 KB 12 KB 70 KB* ~2.9s
Violations
/dashboard js: 52 KB > 40 KB (over by 12 KB)
/dashboard total: 70 KB > 64 KB (over by 6 KB)
✗ 1 of 2 route(s) over budget — 2 violation(s)
* over budget · TTI~ is an unmeasured heuristic estimate (profile MBN)gomani budget check exits 0 when every route is within budget and 1 on any violation, so it
drops straight into CI. --json emits the machine-readable report; --no-color disables ANSI.
Options
| Flag | Meaning |
| ------------------- | ------------------------------------------------------------------------ |
| --config <path> | Budget config (default: search gomani.budget.json / gomani.config.*) |
| --out <dir> | Build output dir assets are sized from (default ./dist) |
| --manifest <path> | Manifest, or bundler stats for --adapter vite\|webpack |
| --adapter <name> | gomani (default) | vite | webpack |
| --cwd <dir> | Project root |
| --json | Emit JSON instead of the table |
| --no-color | Disable ANSI colour |
On TTI
The TTI~ column is a documented heuristic, never a measurement (EstimatedTti.measured is
always false): base + network(latency + throughput) + JS execute-on-a-weak-device, calibrated per
baseline profile (MBN, the 3G-class + entry-Android default; fast for contrast). The
benchmark harness replaces it with real measured TTI on throttled profiles.
Programmatic API
import { runBudgetCheck, analyze, formatReport } from '@gomani/budget';
const { report, ok } = await runBudgetCheck({ cwd: process.cwd() });
console.log(formatReport(report, { color: true }));
if (!ok) process.exitCode = 1;License
MIT © Venancio Gomani / Kwacha Kulture.
