Bundle size: the core /wallet subpath and shell-safe helpers
An app has a SHELL (the code in the initial bundle: a connect flow, a failure presenter, a router) and LAZY chunks (the swap and pool screens) that use the whole SDK. This page says what the shell can import without paying for the rest.
The core /wallet subpath
Since 2.0.0 the subpath lives in the peer package: @gala-chain/gswap-sdk/wallet
no longer exists. @gala-chain/gala-core-sdk/wallet holds only the
dependency-free wallet helpers and never loads the error catalog or the rest of
the SDK:
import { isGalaErrorLike, isWalletUserRejection, walletDeclineCode } from '@gala-chain/gala-core-sdk/wallet';
isWalletUserRejection(value): did the person decline? (see Error Handling, "Did the person decline?")walletDeclineCode(value): the wallet's owncode(4001,'ACTION_REJECTED'), the same reader that fillserror.walletCode.isGalaErrorLike(value)(and the typeGalaErrorShape; namedisGSwapErrorLikeandGSwapErrorShapebefore 2.0.0): recognises an SDK error by a brand (Symbol.for('@gala-chain/gala-core-sdk/error')) or by the documented shape (a stringcodeand an objectparams), neverinstanceof, so it also works when two copies of the SDK are in one page.
The core main entry re-exports the same functions from the same source modules. The
subpath is built as its own self-contained bundle (dist/wallet.mjs,
dist/wallet.cjs, dist/browser/wallet.js), so it does not depend on the app
bundler's tree shaking at all: the built browser file is about 1.2 kB.
packages/gala-core-sdk/tests/wallet_entry.test.ts and core's check:pack fail if the
subpath's bundle contains any module besides its own, has any import, or exceeds 2048 bytes
minified. core's exports["./wallet"] carries types, browser, import and
require conditions, and the package declares "sideEffects": false.
Use it in every flow that has no SDK call of its own (a connect or registration
flow, an analytics hook, a route guard). Measured with rolldown, a file whose only
SDK import is isWalletUserRejection was 85,089 bytes minified from the rc.6 main
entry (the function reached GSwapSDKError and the whole catalog) and is 986
bytes from the subpath.
Shell-safe helpers on the main entry
The key, failure-view and wallet helpers (compositeKeyOf, tryParseCompositeKey,
tryParseTokenClassKey, toFailureView, isWriteView, FAILURE_OUTCOMES,
isFetchTransportFailure, isValidUniqueKey, isWalletUserRejection and the rest)
moved to @gala-chain/gala-core-sdk in 2.0.0. Their budgets are enforced by core's
tree-shaking test, packages/gala-core-sdk/tests/tree_shaking.test.ts (for example
isWalletUserRejection 1,536 bytes). The table and budgets below are the helpers
that stay in this package. The deciders reach core's light modules (the failure view
and core's phase table) through the peer package.
The browser build of the main entry is a folder of preserved modules (one file per
source module, dist/browser/), so a bundler that honours "sideEffects": false
loads only the modules an import reaches. The import / require builds
(dist/index.mjs, dist/index.cjs, for Node) are still one unminified file each.
A bundler puts every module that the shell and a lazy chunk both reach into the
initial load WHOLE, so a helper is only as light as the module it lives in. The
helpers below each live in a module that imports neither GSwapSDKError nor the
error catalog:
| Module | Helpers |
|---|---|
utils/classification.ts (imports nothing) | classification, NOT_QUEUED_FINAL, notSentClassification, FailureClassification |
utils/failure_classification.ts | classifyFailure, mayHaveBeenQueued (the table of every error code) |
utils/failure_guards.ts | isNoMarket, isRelayableRefusal, isUniqueKeyConsumed, isUnprovenAcknowledgement, isUninterpretedAnswer, chainErrorKeyOf |
classes/pending_swap_fate.ts | pendingSwapFateFor, pendingSwapFateOfOutcome, PENDING_SWAP_FATES |
classes/storage_adapters.ts (imports nothing) | webStorageAdapter, storageAdapterFromChromeStorage |
utils/tick_range.ts, utils/tick_align.ts (import nothing) | isTickInRange, alignTickDownOrNaN, alignTickUpOrNaN |
utils/tick_math.ts (only decimal.js and bignumber.js) | tickToPrice, tickFromPrice, isSqrtPriceInRange, GC_MIN_TICK, GC_MAX_TICK |
utils/confirmation_state.ts | confirmationStateOf, isConfirmationAborted, isConfirmationTimeout |
A function that throws an SDK error is not shell-safe, by construction. Each has a
non-throwing sibling in a light module: alignTickDownOrNaN / alignTickUpOrNaN
for alignTickDown / alignTickUp, tryParseCompositeKey /
tryParseTokenClassKey (from @gala-chain/gala-core-sdk) for parseTokenClassKey, and NaN from tickToPrice /
tickFromPrice. A shell that needs the class itself imports the whole SDK
lazily.
Budgets
The initial-load budget of each helper, measured in the shell shape (a static
import { X } in the entry plus a lazy chunk that does import * as sdk),
minified bytes, through the packed tarball, with about 20% margin:
| Helper | Budget (measured) |
|---|---|
classification, NOT_QUEUED_FINAL | 512 (363) |
isTickInRange | 512 (294) |
alignTickDownOrNaN, alignTickUpOrNaN | 512 (251) |
ALL_FEE_TIERS, TICK_SPACING_BY_FEE | 512 (369) |
webStorageAdapter, storageAdapterFromChromeStorage | 768 (478) |
confirmationStateOf, isConfirmationAborted, isConfirmationTimeout | 1,792 (1,376) |
isNoMarket, isRelayableRefusal, isUniqueKeyConsumed, chainErrorKeyOf | 2,560 (2,027) |
classifyFailure, mayHaveBeenQueued | 9,216 (7,772) |
pendingSwapFateFor | 9,728 (7,943) |
tickToPrice, tickFromPrice, isSqrtPriceInRange | 62,464 (53,674) |
The decider family carries the table of every error code (about 135 names, 4 kB of
strings no minifier removes) and the phase table, but no class and no catalog
templates. It reaches core's light modules (the failure view and core's phase
table) through @gala-chain/gala-core-sdk, which stays a peer dependency of the
app. The combined shell of this package's helpers measures 64,114 bytes. The three price functions are the two number libraries they compute with
(decimal.js and bignumber.js, about 53 kB together) and about 1.3 kB of the SDK;
an app that already ships both pays only the SDK's part.
tests/shell_shape.ts holds the table (SHELL_SAFE_HELPERS) and, when a helper
breaks its budget, names the modules that came with it. tests/tree_shaking.test.ts
runs it from src (rolldown), npm run check:pack from the packed tarball through
the browser condition, and GSWAP_VITE_PACKAGE=<a vite package directory> npm test
repeats it through a real Vite build (which adds Vite's own ~1.2 kB dynamic-import
preload helper; the test subtracts it). A second test walks the run-time import
graph of every light module from its source and fails on any path to the class or
the catalog.
To print the numbers yourself:
tsx scripts/measure-shell-shape.ts classification compositeKeyOf
tsx scripts/measure-shell-shape.ts --entry @gala-chain/gswap-sdk --cwd /path/to/app classifyFailure
tsx scripts/measure-shell-shape.ts --vite /path/to/node_modules/vite classifyFailure