Do not take the numbers on this site on faith. Here is how to get them in your own project.
Why bother
Because "tree-shakeable" is a claim, and yours is the only bundle that matters. A library can be perfectly tree-shakeable and still land whole in your build — one import * as, one lookup by string, one barrel file, and the bundler stops being able to prove what is unused.
How
Build twice and subtract. First, ng build --configuration production as you have it today; note the gzip size of the entry chunks. Then add the icon and build again. The difference is what the icon cost you — not what anyone promised.
To see why a number is what it is, build with --stats-json and open the result in any bundle analyser. What you are looking for is whether the icon catalog appears whole: if you imported bellIcon and the output mentions icons you never named, something is anchoring the registry.
The usual culprit is name="bell" with provideIconCatalog(ANIMATED_ICONS). That path is a convenience and it is documented as such: a lookup by string cannot be tree-shaken, so it pulls the whole catalog on purpose. If you want the small number, pass the icon by value with [iconDef].
What to expect
Measured in CI on every push against the published package:
- One icon — around 13.7 KB gzip net over an empty app, engine included.
- Ten icons — around 15.2 KB. The engine is paid once; each icon adds roughly 0.17 KB.
- The whole catalog via
name=— over 100 KB. That is the trade, and it is the reason the catalog is opt-in.
If your numbers are far above these, the difference is in your build, not in the package — and the stats file will say where.