Wado

Research: Splitting Large Libraries into Components

How to break a large library (think ICU4X, but the reasoning is general) into Wasm Component Model (CM) pieces so a program pays only for what it uses. This is a findings document grounded in two measured spikes under wado-bundled-icu/:

The two things you split: code and data

A large library's footprint has two very different parts:

Splitting strategy differs per part. Code is shrunk by narrowing the surface; data is shrunk by not baking what you don't use and not storing what you use twice.

What the Component Model lets you share

CM components have separate linear memories. The only things that cross a component boundary are Canonical-ABI values — string, list, record, enum, result, and resource handles. Consequences:

This last point is the lever that makes data sharing possible despite separate memories.

Three levers

  1. Split by feature (surface narrowing). Put independent capabilities behind separate WIT exports / components. LTO then keeps only the code each one reaches. A program embeds only the feature components it uses, so unused features — and their data — never ship.

  2. Separate data from code (runtime data provider). Build feature components without baked data and have them load a serialized data blob at runtime through a provider abstraction. The blob is produced offline by a datagen step that includes only the markers the chosen features need. This turns data into a separate, sliceable, swappable artifact and makes feature components tiny.

  3. Compose a shared data component. Bake the blob into one component that exports it, and have feature components import it. Composition wires them into a single self-contained artifact, so "the shared part lives in its own component, the others use it" is realized literally — for data, the thing that actually crosses the boundary as bytes.

Levers 2 and 3 only help where data is the cost. Lever 1 is always the first move, because the biggest data is usually feature-specific and simply absent when you don't embed that feature.

ICU4X: what we measured

ICU4X is compiled_data by default (every component bakes its CLDR/Unicode data). It also exposes *_with_buffer_provider constructors, BlobDataProvider, and an offline datagen — exactly the lever-2/3 machinery. The spike exercised all three levers; the load-bearing results:

Principles