Skip to content
Comvi

Bundle size

View .md

What each piece of Comvi i18n weighs, and which import adds it.

Figures are min+gz, produced by pnpm size and measured through each package’s published exports map rather than a dist/ path, so what is measured is what an installed app resolves. A framework’s own runtime is left out, so a framework row is the Comvi code only.

CI re-measures every row against its recorded baseline with 5% of headroom and fails when a row exceeds that budget, so a regression inside the margin passes.

app shape measured as min+gz
@comvi/core alone, nothing composed core-base 5270 B
@comvi/core + ICU core-base-icu 6502 B
every core capability composed core-full-composite 9389 B
@comvi/react, bare instance + bindings fw-react-default 7369 B
@comvi/react, every capability composed fw-react-full-composite 12262 B
@comvi/react + ICU + the CDN loader platform-path-react 11353 B
core + ICU + the CDN loader plugin-fetch-loader 9692 B

Every figure names its fixture, and each fixture is a gated row in scripts/size-budgets.json in the comvi-js repository. Rows one and two give the price of ICU, 1232 B, which is why it is the compiler constructor option rather than a default. Rows one and four give the price of the React bindings over the core floor, 2099 B. Rows four and five bracket a React app: the bindings alone against everything composed.

core-full-composite recomposes /tags, /icu, /loader, /plugins and /devtools.

The root entry of @comvi/plugin-fetch-loader is the CDN request path on its own. fetchLoader from @comvi/plugin-fetch-loader/api chooses between the CDN and the API at runtime, so it carries both request paths whether or not you reach them.

graph measured as min+gz
bare instance, ICU, and the /api entry plugin-fetch-loader-api 11711 B
bare instance, ICU, and the root entry plugin-fetch-loader 9692 B

An app that only reads a public bundle swaps fetchLoader for cdnLoader and drops 2019 B with the API path. Keep fetchLoader wherever the i18n instance has an apiKey. See CDN mode vs API mode.

The import-map adapter behind .use(loader(map)) is in your graph only when you hand over a map: attachLoader does not name it, so an instance that registers a plain loader function never carries it.

Every capability is an import you add, so the floor is the bare instance and each capability is a line in your own composition.

  • Nothing arrives switched off. An absent capability’s module never entered the bundle, which is why a missing one is a TypeScript error rather than a runtime no-op.
  • No eval and no new Function in any runtime package, so everything runs under a strict CSP without unsafe-eval.
  • @comvi/core has zero runtime dependencies.
  • The unpkg / jsdelivr global build is the one exception and still carries everything: a <script src> consumer has no import graph to extend.
  • .use(installer): the i18n instance, and what each installer adds to it.
  • Fetch loader: why the root entry carries two request paths, and when to use which.
  • Pluralize with ICU: what the 1232 B buys: plural, select and selectordinal per framework.