Bundle-split TS code#397
Open
markmur wants to merge 8 commits into
Open
Conversation
Package Size
Web file breakdown
React Native file breakdown
Android file breakdown
Measured from the PR base SHA and PR head SHA. The file breakdown shows uncompressed sizes within each package artifact, so individual files do not sum to the compressed artifact total. This comment reports package artifact sizes only; it is not a final app binary-size report. |
faa1b1e to
4bec16a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes are you making?
Shrinks the web bundle by removing the quicktype
Convert/typeMapruntime from the decode path and letting the web build tree-shake it out.Before: the generated
typeMapboth validates (recursively) and remaps snake_case ↔ camelCase. It's resolved by string key, so it can't be tree-shaken while anyConvert.*method is referenced — it shipped in the web bundle in full (~25 KB).After:
SHAPES) + a small generated required-field table (REQUIRED), emitted bygenerate_case_map.mjsintogenerated/CaseMap.ts.case_transform.ts:camelizeKeys/snakeifyKeys) that renames keys mechanically and recurses typed dictionaries while preserving dynamic map keys verbatim.sideEffects: falseon the protocol TS package so the web build can drop the now-unreferencedConvertruntime.Measured impact (web bundle, vs base branch)
dist/index.js(raw)dist/index.js(gzip)dist/index.js.mapThe quicktype runtime is confirmed absent from the built bundle (its
Expected … but got …error string is gone). The Package Size check reports exact deltas on this PR.Tests: protocol 43/43, web 116/116 (100% line coverage), React Native 18/18.
Tradeoffs
1. Remapping moves from a validated typeMap to a generated skeleton + generic walker.
The walker is now the single decode path for every consumer of the TS protocol package (web and React Native). Correctness depends on the generated
SHAPESskeleton staying in sync with the models — it is regenerated as part of the codegen pipeline (generate_models.sh→generate_case_map.mjs), so it can't drift by hand. One sharp edge this surfaced: dictionaries whose values are typed objects (e.g.ucp.payment_handlers,ucp.services) must carry their element type inSHAPESso the walker recurses into the values while leaving the dynamic keys untouched; free-form maps (e.g.constraints) are left verbatim.2. Decode validation is now top-level only (not recursive).
camelizeKeysvalidates required top-level fields (presence, plustypeoffor string-typed fields) and still returns JSON-RPCINVALID_PARAMS(-32602) when the top-level payload is missing or the wrong shape. It intentionally does not reproduce the old recursive quicktype validation, so it no longer catches:line_items/links/totals/ucp/statusare presence-only),Why this is an acceptable trade: payloads on this boundary are first-party (the Shopify checkout iframe), the layer's actual job is snake ↔ camel remapping, and recursive validation is brittle against protocol version skew — a single unrecognized nested field could reject an entire checkout update and break the UI. Presence-checking the top level keeps the "reject obviously malformed params" contract without that fragility.
Restoring deeper validation later is byte-cheap:
REQUIREDalready enumerates every type, so it can be walked recursively without regenerating anything.Follow-up (not in this PR)
The
{checkout}/{error}params envelope narrowing still lives in the protocol descriptors. It's slated to move into each platform kit so the protocol package stays purely wire-level.Before you merge
Important
platforms/swift/README.mdand/orplatforms/android/README.md)Releasing a new Swift version?
ShopifyCheckoutKit.podspecplatforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swiftplatforms/swift/README.md(major version only)Releasing a new Embedded Checkout Protocol version?
embeddedCheckoutProtocolAndroidinplatforms/android/gradle/libs.versions.tomlprotocol/languages/kotlin/embedded-checkout-protocol/api/embedded-checkout-protocol.apiif the public API changedReleasing a new Android version?
checkoutKitAndroidinplatforms/android/gradle/libs.versions.tomlplatforms/android/README.mdTip
See the Contributing documentation for the full release process per platform.