Skip to content

Bundle-split TS code#397

Open
markmur wants to merge 8 commits into
web-ts-protocolfrom
web-protocol-bundle-split
Open

Bundle-split TS code#397
markmur wants to merge 8 commits into
web-ts-protocolfrom
web-protocol-bundle-split

Conversation

@markmur

@markmur markmur commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

What changes are you making?

Shrinks the web bundle by removing the quicktype Convert/typeMap runtime from the decode path and letting the web build tree-shake it out.

Before: the generated typeMap both validates (recursively) and remaps snake_case ↔ camelCase. It's resolved by string key, so it can't be tree-shaken while any Convert.* method is referenced — it shipped in the web bundle in full (~25 KB).

After:

  • A generated structural remap skeleton (SHAPES) + a small generated required-field table (REQUIRED), emitted by generate_case_map.mjs into generated/CaseMap.ts.
  • A hand-written walker (case_transform.ts: camelizeKeys / snakeifyKeys) that renames keys mechanically and recurses typed dictionaries while preserving dynamic map keys verbatim.
  • sideEffects: false on the protocol TS package so the web build can drop the now-unreferenced Convert runtime.

Measured impact (web bundle, vs base branch)

Artifact Before After Δ
dist/index.js (raw) 48,698 B 29,374 B −19,324 B (−39.7%)
dist/index.js (gzip) 9,684 B 7,749 B −1,935 B (−20.0%)
dist/index.js.map 184,211 B 95,273 B −88,938 B (−48.3%)

The 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 SHAPES skeleton staying in sync with the models — it is regenerated as part of the codegen pipeline (generate_models.shgenerate_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 in SHAPES so 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).

camelizeKeys validates required top-level fields (presence, plus typeof for string-typed fields) and still returns JSON-RPC INVALID_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:

  • missing nested required fields,
  • non-string type errors on top-level structural fields (line_items / links / totals / ucp / status are presence-only),
  • enum value mismatches.

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: REQUIRED already 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

  • I've added tests to support my implementation
  • I have read and agree with the Contribution Guidelines
  • I have read and agree with the Code of Conduct
  • I've updated the relevant platform README (platforms/swift/README.md and/or platforms/android/README.md)

Releasing a new Swift version?
  • I have bumped the version in ShopifyCheckoutKit.podspec
  • I have bumped the version in platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift
  • I have updated the SwiftPM/CocoaPods version snippets in platforms/swift/README.md (major version only)
Releasing a new Embedded Checkout Protocol version?
  • I have bumped embeddedCheckoutProtocolAndroid in platforms/android/gradle/libs.versions.toml
  • I have updated protocol/languages/kotlin/embedded-checkout-protocol/api/embedded-checkout-protocol.api if the public API changed
Releasing a new Android version?
  • I have bumped checkoutKitAndroid in platforms/android/gradle/libs.versions.toml
  • I have updated the Gradle/Maven version snippets in platforms/android/README.md

Tip

See the Contributing documentation for the full release process per platform.

@markmur markmur self-assigned this Jul 2, 2026
@markmur markmur requested a review from a team as a code owner July 2, 2026 09:15
@github-actions github-actions Bot added the #gsd:50662 Rebase Checkout Kit on UCP label Jul 2, 2026
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

Package Size

Platform Artifact Base Head Delta
Web npm tarball 66.6 KiB 48.1 KiB -18.5 KiB
React Native npm tarball 99.4 KiB 96.4 KiB -3.0 KiB
Android release AAR 160.8 KiB 160.8 KiB 0 B
Web file breakdown
File Base Head Delta
dist/index.js.map 179.9 KiB 75.9 KiB -104.0 KiB
dist/index.js 47.6 KiB 22.2 KiB -25.4 KiB
dist/custom-elements.json 38.0 KiB 38.0 KiB 0 B
src/checkout.ts 26.5 KiB 26.5 KiB 0 B
README.md 16.4 KiB 16.4 KiB 0 B
dist/checkout.d.ts 6.9 KiB 6.9 KiB 0 B
src/checkout.types.ts 4.1 KiB 4.1 KiB 0 B
dist/checkout.types.d.ts 3.0 KiB 3.0 KiB 0 B
package.json 2.9 KiB 2.9 KiB 0 B
src/checkout.styles.ts 2.8 KiB 2.8 KiB 0 B
src/utils.ts 1.7 KiB 1.7 KiB 0 B
dist/utils.d.ts 1.4 KiB 1.4 KiB 0 B
src/index.ts 1.2 KiB 1.2 KiB 0 B
LICENSE 1.1 KiB 1.1 KiB 0 B
dist/index.d.ts 738 B 738 B 0 B
src/checkout-web-component.ts 271 B 271 B 0 B
dist/checkout-web-component.d.ts 154 B 154 B 0 B
dist/checkout.styles.d.ts 79 B 79 B 0 B
React Native file breakdown
File Base Head Delta
node_modules/@shopify/checkout-kit-protocol/src/generated/Models.ts 85.8 KiB 51.5 KiB -34.4 KiB
node_modules/@shopify/checkout-kit-protocol/src/generated/Models.d.ts 53.2 KiB 51.7 KiB -1.5 KiB
ios/ShopifyCheckoutKit.swift 15.0 KiB 15.0 KiB 0 B
ios/AcceleratedCheckoutButtons.swift 14.0 KiB 14.0 KiB 0 B
lib/commonjs/index.js 13.1 KiB 13.1 KiB 0 B
src/components/AcceleratedCheckoutButtons.tsx 12.9 KiB 12.9 KiB 0 B
src/index.ts 12.5 KiB 12.5 KiB 0 B
lib/commonjs/components/AcceleratedCheckoutButtons.js 11.4 KiB 11.4 KiB 0 B
android/src/main/java/com/shopify/reactnative/checkoutkit/ShopifyCheckoutKitModule.java 11.1 KiB 11.1 KiB 0 B
lib/module/index.js 10.4 KiB 10.4 KiB 0 B
lib/commonjs/components/AcceleratedCheckoutButtons.js.map 10.3 KiB 10.3 KiB 0 B
lib/module/components/AcceleratedCheckoutButtons.js 10.2 KiB 10.2 KiB 0 B
lib/module/components/AcceleratedCheckoutButtons.js.map 9.1 KiB 9.1 KiB 0 B
src/index.d.ts 8.9 KiB 8.9 KiB 0 B
node_modules/@shopify/checkout-kit-protocol/src/generated/ProtocolNotifications.ts 8.5 KiB 8.5 KiB +31 B
lib/module/index.js.map 8.2 KiB 8.2 KiB 0 B
src/present-dispatcher.ts 8.0 KiB 8.0 KiB 0 B
lib/commonjs/index.js.map 7.7 KiB 7.7 KiB 0 B
lib/commonjs/present-dispatcher.js 6.8 KiB 6.8 KiB 0 B
lib/module/present-dispatcher.js 6.5 KiB 6.5 KiB 0 B
…and 109 smaller files
Android file breakdown
File Base Head Delta
classes.jar 170.2 KiB 170.2 KiB 0 B
res/layout/dialog_checkout.xml 1.3 KiB 1.3 KiB 0 B
proguard.txt 798 B 798 B 0 B
AndroidManifest.xml 578 B 578 B 0 B
res/values/values.xml 564 B 564 B 0 B
R.txt 522 B 522 B 0 B
res/drawable/close.xml 431 B 431 B 0 B
res/menu/checkout_menu.xml 354 B 354 B 0 B
META-INF/com/android/build/gradle/aar-metadata.properties 157 B 157 B 0 B

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.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

React Native — Coverage Report

Lines Statements Branches Functions
Coverage: 92%
91.85% (327/356) 87.98% (183/208) 100% (86/86)

@markmur markmur force-pushed the web-protocol-bundle-split branch from faa1b1e to 4bec16a Compare July 2, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

#gsd:50662 Rebase Checkout Kit on UCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant