sveltelean
Versionv0.2.0 GitHub

How budgets work

Each package's yarn size builds its entry points, compares the compressed size with the budget written in the script, records both in artifacts/size.json and exits with an error when the budget is exceeded. yarn verify runs it, so a pull request cannot pass with a regression of that size. A budget is raised only with the reason in the commit and a changeset (Methodology).

Behavior JavaScript

Each Tier 1 registration module built with Vite in production mode, including the shared kernel. The budget is brotli; the same script also requires the bundle to contain no diagnostic marker and to keep the registration side effect.

SubjectEntryBudgetMeasuredHeadroomStatus
tabsvite1700 B brotli1521 B brotli179 Bwithin budget
menuvite2100 B brotli1932 B brotli168 Bwithin budget
listboxvite2000 B brotli1838 B brotli162 Bwithin budget
comboboxvite2900 B brotli2564 B brotli336 Bwithin budget
selectvite3700 B brotli3362 B brotli338 Bwithin budget
calendarvite4300 B brotli3925 B brotli375 Bwithin budget
date-pickervite5400 B brotli4912 B brotli488 Bwithin budget
tooltipvite1400 B brotli1297 B brotli103 Bwithin budget
toastvite1600 B brotli1396 B brotli204 Bwithin budget
treevite2100 B brotli1919 B brotli181 Bwithin budget
range-slidervite1400 B brotli1291 B brotli109 Bwithin budget
number-fieldvite1200 B brotli1082 B brotli118 Bwithin budget
togglevite1000 B brotli888 B brotli112 Bwithin budget
toggle-groupvite1800 B brotli1569 B brotli231 Bwithin budget
toolbarvite1700 B brotli1494 B brotli206 Bwithin budget
splittervite1900 B brotli1683 B brotli217 Bwithin budget
context-menuvite1600 B brotli1409 B brotli191 Bwithin budget
file-dropvite1300 B brotli1107 B brotli193 Bwithin budget
hover-cardvite1500 B brotli1353 B brotli147 Bwithin budget
menubarvite1700 B brotli1457 B brotli243 Bwithin budget

Script: packages/primitives/scripts/size.mjs. Values from packages/primitives/artifacts/size.json; method: ESM, target es2022, gzip level 9, brotli quality 11 (node:zlib). Tier 1 and Tier 2 entries are dist/<name>/register.js with @svelte-lean/core from the workspace. "vite" builds the public specifier with Vite in production mode; the brotli budget applies to it and it must list no diagnostics and keep the registration. "esbuild" bundles the same file with esbuild under the production condition; it keeps development helpers core references from folded DEV gates and is recorded for comparison. "core-only" is a registration with an empty handler. "native-only" imports the root entry and a Tier 0 subpath and must contain no runtime.

Kernel

The root entry of @svelte-lean/core with every export, under the production condition and under the runtime-detected environment module, and what one Tier 1 behavior pulls in when built with Vite. The budget is gzip and applies to all three.

SubjectEntryBudgetMeasuredHeadroomStatus
productionesbuild2500 B gzip2113 B gzip387 Bwithin budget
defaultesbuild2500 B gzip2197 B gzip303 Bwithin budget
consumervite2500 B gzip994 B gzip1506 Bwithin budget

Script: packages/core/scripts/size.mjs. Values from packages/core/artifacts/size.json; method: ESM, target es2022, gzip level 9, brotli quality 11 (node:zlib). "production" and "default" are dist/index.js with every export, esbuild bundle + minify, under the production export condition and the runtime-detected env module respectively. "consumer" is one Tier 1 behavior using parts and emit, built with Vite in production mode; it must list no diagnostics.

Table entry points

Every entry of @svelte-lean/table bundled on its own with esbuild, Svelte excluded; shared code is counted once per entry here and de-duplicated by a consumer bundler. Budgets are gzip.

SubjectEntryBudgetMeasuredHeadroomStatus
rendererdist/index.js22000 B gzip20031 B gzip1969 Bwithin budget
headlessdist/core.js2700 B gzip2475 B gzip225 Bwithin budget
enginedist/table.svelte.js3600 B gzip3494 B gzip106 Bwithin budget
groupingdist/grouping.js2400 B gzip2148 B gzip252 Bwithin budget
pivotdist/pivot.js600 B gzip526 B gzip74 Bwithin budget
editingdist/editing.js800 B gzip707 B gzip93 Bwithin budget
csvdist/export.js850 B gzip741 B gzip109 Bwithin budget
clipboarddist/clipboard.js1000 B gzip895 B gzip105 Bwithin budget
serverdist/server.js425 B gzip369 B gzip56 Bwithin budget
statedist/state.js900 B gzip796 B gzip104 Bwithin budget
stylesdist/style.css7300 B gzip6665 B gzip635 Bwithin budget

Script: packages/table/scripts/size.mjs. Values from packages/table/artifacts/size.json; method: Each entry bundled independently with esbuild (bundle + minify, ESM); shared code is counted per entry here and de-duplicated by consumer bundlers. Svelte peer runtime excluded. gzip level 9 / brotli quality 11 (node:zlib). Budgets are gzip.

Styles

The resolved index.css, every import inlined, minified. The budget is gzip and covers the whole package; single files are measured and listed on the Results page without a budget of their own.

SubjectEntryBudgetMeasuredHeadroomStatus
index.css (resolved)–21600 B gzip20765 B gzip835 Bwithin budget

Script: packages/styles/scripts/size.mjs. Values from packages/styles/artifacts/size.json; method: bytes = shipped source; minified = comments and redundant whitespace removed by scripts/check.mjs minify (a bundler minifier may be slightly smaller); gzip level 9 and brotli quality 11 of the minified text. standalone = the file with the files it @imports inlined. "index.css (resolved)" inlines every @import once, depth first, and carries the budget.

Targets

ADR 0003 states initial targets for the behavior sizes and marks them as aspirational, to be published only once build output proves them. They are quoted here from the ADR text and compared with the measured values, whichever way the comparison goes.

Tabs < 1 kB brotli, basic Menu ~1–2 kB, entire common behavior set < 5 kB.
SubjectTarget (aspirational)MeasuredEnforced budgetResult
Tabs registration with the kernel1000 B brotli1521 B brotli1700 B brotliabove the target, within the enforced budget
Menu registration with the kernel1000–2000 B brotli1932 B brotli2100 B brotliwithin the range
Entire common behavior set (tabs and menu on one page, one kernel)5000 B brotli2351 B brotlinone: measured by the tabs-and-menu fixture, not gatedwithin the target
Native primitives (button, dialog, popover, disclosure, checkbox, switch, radio group)no behavior JavaScript0 B brotlithe native-only fixture forbids every runtime modulemet

Where a measured value sits above an aspirational target, the target stays in the ADR as a direction and the enforced budget is the gate. The two are different things: a target says where the architecture wants to go, a budget says what a release may not exceed.

Tier budgets

Every primitive declares one runtime tier in its contract, and each tier is a budget of a different kind: not bytes, but what a primitive may cost at runtime (ADR 0003).

TierNameBudget
0NativeNo runtime JavaScript, no instance listeners, no instance state objects
1Delegated micro-behaviorOne shared listener per required event type; no per-root listener; DOM-encoded state
2Lazy scoped controllerWeakMap state created on first interaction; AbortController-scoped listeners; cleanup
3Application-controlledSvelte state owned by the application; never required by a default primitive

Listener budget

A Tier 1 behavior installs one listener per event type it declares, on the document runtime, regardless of how many roots are on the page. The gate is an exact equality in listeners.spec.ts: the per-type counts for a thousand tabs roots equal the counts for one root, on the runtime's account and on an independent count of every addEventListener call. No number in a file holds this budget; the assertion is the budget. The Results page reads the live counts of this site and the proof page mounts a thousand roots on demand.

Tier 2 has a budget of its own: lazy state created on first interaction and released with its listeners. The combobox is the Tier 2 behavior; its register module carries the brotli budget in the table above, and the lazy-state budget is an exact assertion, not a number: combobox.test.ts holds no state for a thousand untouched roots and lazy.spec.ts reads zero controllers after load for a hundred roots in Chrome, one per interacted root, released on close and on focus loss.