Build1 distinct publisher3 min readUpdated
A UI library maintainer measured the same directive three defensible ways and got 6.0 kB, 9.8 kB, and less. The spread is not noise; it is three different questions.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The maintainer of ShipUI, a zoneless signal-based Angular component library with no runtime dependencies, set out to publish honest per-component byte costs and could not get the measurements to agree [1][2]. The same sortable directive came out at 6.0 kB gzipped under one method and 9.8 kB gzipped under another, with a third method producing something smaller again for developers already using the library [4].
Method one builds each component's own bundle minified with `external: ['*']`, so shared Angular code, rxjs and the library's internal utilities are excluded from the count [5]. The author is explicit that this is the floor: it measures how much code he wrote, not how much your application grows [6]. Method two is the delta test. Build an empty zoneless app, note the gzipped size, add one namespace import of the component, build again, subtract [7]. Every build runs the production pipeline, so AOT, esbuild and tree shaking all apply, and subtracting the baseline removes Angular's fixed runtime cost [7]. The namespace import is pinned alive with a global `__keep` reference specifically so tree shaking cannot drop unused exports and hand back a flattering number [8]. That discipline is the part most vendor size tables skip.
The headline in the original post says the answers are 3x apart [3], but the published pair for the sortable directive is 6.0 versus 9.8, a ratio of about 1.6 [1]. The real spread shows up elsewhere, in the second experiment. Measured alone against an empty app, button-group comes in at roughly 11.5 kB and tabs at roughly 11.2 kB, a naive sum of about 22.7 kB [10]. Built together, the pair costs about 12.0 kB [10]. The overcount is roughly 10.7 kB, meaning the additive reading is about 1.9 times the measured truth [2].
The cause is unremarkable and that is the point. Both components extend a shared selection-group base class handling roving focus, aria wiring and keyboard navigation, which itself pulls in a keybindings service and internal utilities [11]. Measured in isolation, each component is charged for the whole chain; in a real build the chain ships once [11][13]. So the marginal cost of the second component is about 0.5 kB [3], which the author describes as under 1 kB [12], or roughly 4 percent of its own standalone figure [3]. Against tabs measured alone, that is a spread of at least 11x on one component depending on what else is in the bundle [4].
Practically, there are three questions and they do not share an answer. How much code did the author write. What does the first use cost in an otherwise empty app. What does the nth use cost in an app that already carries the shared base. Adding up rows in a size table answers none of them, because it charges shared code once per component instead of once per bundle [13]. The author's inversion holds: the more of the library you adopt, the cheaper each additional component gets, and a per-component table hides exactly that [14].
What to watch: whether any component library ships size numbers labelled with the method and the baseline, and whether the delta-against-empty-app figure gets paired with a marginal figure for an app that already imports a sibling. Until then, treat a single kB badge as a floor and measure your own build before and after. The tooling in this write-up is a few lines of Bun and a subtraction [5][7].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The author has been building ShipUI for about 3 years, described as a zoneless signal based Angular UI library with zero runtime dependencies.
For one component, a sortable directive, the three measurements were 6.0 kB gzipped, 9.8 kB gzipped, and something smaller again once you already use the library.
Measured each against an empty app, button-group came to about 11.5 kB and tabs to about 11.2 kB, a naive sum of about 22.7 kB, while building both together in one build produced about 12.0 kB.
The author states the second component's real cost is under 1 kB, because the base class, keybindings service and shared utils are in the bundle once instead of twice.
The author states the effect is backwards from expectation: the more of the library you use, the cheaper each new component gets as shared code amortizes, and a component-by-component size table hides this because every row re-pays the shared cost.
The author wanted to publish honest per-component sizes on the library's site, such as what a button actually costs you, and found it harder than expected because the question has about three different answers depending on how it is measured.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Method disclosed, results unreproduced
The post shows its actual measurement code (Bun.build flags, baseline/delta builds, the __keep tree-shaking guard) and reports specific gzipped figures, which is unusually concrete for a blog claim. But every number comes from one self-published source authored by the measured library's own maintainer, no third party reproduces them, and the promised full per-component table is truncated in the supplied text, so the headline figures cannot be inspected. Internal consistency is also imperfect: the '3x apart' framing is not supported by the two quantified sortable figures.
No adoption signal in sources
The supplied source reports no downloads, dependents, deployments, releases, pricing, licensing or third-party usage for ShipUI or for the measurement harness. Library age and architecture are stated, but age is not adoption, and no other party is shown to have run the recipe. There is nothing to measure without inferring facts the source does not provide.
Slightly overstated framing, sound core
The substance is modest and self-critical: the author labels his smallest number a floor, warns against putting it on a landing page, and hands readers a script to check him. The overstatement is narrow and in the framing — the '3x apart' headline is not borne out by the only quantified pair given (6.0 kB vs 9.8 kB, about 1.6x), and the third figure is never quantified. A generalized claim that per-component tables are misleading rests on one two-component experiment inside a single library, with no adoption evidence anywhere, so the reach of the conclusion outruns the demonstrated base slightly.
Maintainer measuring own library
The author is ShipUI's maintainer publishing size figures for ShipUI on a developer platform, and the post doubles as a showcase for the library's small-footprint positioning — a direct interest in favourable numbers. Two factors partially offset this: he publishes the exact build configuration and a reproduction recipe, and he argues explicitly against citing the smaller, more flattering measurement. With only one publisher in the cluster there is no counterweight source.
Single self-interested source
Confidence is limited by structure rather than by internal quality: one publisher, one author, self-reported measurements of his own project, no independent reproduction, no adoption data, and a truncated results table. What raises it above the floor is that the methodology is specific enough to falsify and the derived arithmetic on the disclosed figures is internally checkable.
build
The npm audit that works because it never installs the package1 distinct publisher
build
PrimeNG archived its repo, and Angular teams now own a procurement decision1 distinct publisher
build
Your Next.js rate limiter counts per instance, and Server Actions hide behind the page URL1 distinct publisher
build
A 1.5s speech-to-LLM win came from not sending silence and deleting a classifier1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 18, 2026