Skip to main content

Bundle Size & Module Formats

The SDK ships both a CommonJS and an ESM build, and keeps its two heavy dependencies — Zod and socket.io-client — out of the import graph until they are actually used. A project that calls a single method, leaves validation off and never opens a socket loads 43 kB minified (9.7 kB gzip), down from 536 kB (110 kB gzip).

What ships in the package

FieldValueUsed by
maindist/index.jsNode and any CommonJS consumer
moduleesm/index.jsBundlers (webpack, Vite, Rollup, esbuild)
typesdist/index.d.tsTypeScript
sideEffectsfalseBundlers, to drop unused modules

There is no "exports" map, so every existing deep import — oneentry/dist/<module>/<module>Interfaces and the rest — resolves exactly as it did before. Node keeps resolving the CommonJS build through main; nothing about your current setup has to change.

sideEffects: false tells the bundler that importing a module of the SDK never does anything on its own, which is what makes tree-shaking possible: the modules you do not touch are dropped from the output.

Zod loads only when validation runs

Response validation is disabled by default. The response schemas used to be imported statically by every module, which pulled Zod into every bundle even when nothing was ever validated. Schemas and the validation helpers are now loaded on demand, the first time a response actually has to be validated.

  • With validation.enabled: false (the default), Zod and the per-module schemas (341 kB) end up in chunks that are never requested.
  • With validation.enabled: true, the behaviour is unchanged — the schemas are simply fetched the first time they are needed.
  • In Node, require('oneentry') no longer loads Zod at startup.

For a project that calls a single method with validation off, the code that actually loads drops from 536 kB to 83 kB minified (110 kB → 22 kB gzip) — and down to 43 kB once socket.io is left out as well (see below).

ℹ️ That figure assumes a bundler doing code splitting — the default in webpack, Vite and Rollup. A bundle forced into a single file still shrinks, but only to ~427 kB, because Zod is then inlined even though it never runs.

No public API changed. The internal _validateResponse helper became async, which is only relevant if you extended the SDK's base classes yourself.

socket.io loads only when you open a socket

WS.connect() keeps its synchronous signature and still returns a socket.io Socket, but socket.io-client (~41 kB) is now imported the first time connect() is called.

Until the chunk resolves, the returned object queues whatever you do with it — on, emit, disconnect — and replays it onto the real socket in the same tick the socket is created, before the connection can deliver anything, so no event is lost:

// Nothing changes in normal use — handlers registered here always fire.
const socket = WS.connect();

socket.on('connect', () => console.log('WebSocket connected'));
socket.on('my_event', (payload) => console.log(payload));

Reading connection state early stays accurate, because a freshly created socket is not connected either: id is undefined and connected is false in both the old and the new behaviour.

The one difference: a method that has to return something (for example listeners()) cannot answer before the chunk arrives, and nested objects such as socket.io are reachable only once it is loaded. Registering handlers and emitting — the normal use — is unaffected.

Bundle size at a glance

ScenarioMinifiedGzip
Before (every consumer)536 kB110 kB
Validation off, no socket43 kB9.7 kB
Validation off, socket opened~83 kB~22 kB
Single-file bundle, no code splitting~427 kB

Getting the smallest build

  • Leave validation off in production. Enable it while developing to catch data inconsistencies, then turn it off — the schemas stay out of the loaded code.
  • Let your bundler split code. Code splitting is on by default in webpack, Vite and Rollup; disabling it inlines the lazy chunks and gives most of the win back.
  • Import types with import type. Type imports are erased at compile time — see Importing Types.
  • Only destructure the modules you use. With sideEffects: false and the ESM build, untouched modules are dropped from the output.