Skip to content

[Performance] Replace O(n²) array scans in appDiff with Map/Set lookups - #8599

Draft
github-actions[bot] wants to merge 1 commit into
mainfrom
performance-maintenance-35547738595
Draft

github-actions[bot] wants to merge 1 commit into
mainfrom
performance-maintenance-35547738595

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

WHY are these changes introduced?

appDiff compares the extensions of the previously loaded app against a freshly reloaded one. It runs inside ReloadAppHandler, so it executes on every app reload during shopify app dev — that is, on every relevant file change while the dev server is running.

The implementation scanned the opposite extension array once per extension:

  • newExtensions.filter((ext) => !oldExtensionsUids.includes(ext.uid))
  • oldExtensions.filter((ext) => !newExtensionsUids.includes(ext.uid))
  • oldExtensions.find((oldExt) => oldExt.uid === ext.uid) inside a filter over newExtensions

Each of those is a linear scan nested inside a loop, making the whole function O(n²) in the number of extensions. Apps with many extensions pay this cost on each keystroke-triggered reload, right on the dev feedback loop.

WHAT is this pull request doing?

Index the old extensions by uid in a Map and the new uids in a Set, so every membership test and lookup is O(1) instead of a full array scan. The diff is now O(n) overall.

The Map doubles as both the membership check for created extensions and the lookup for the updated comparison, so only two index structures are built instead of the two uid arrays that existed before — no extra allocation.

Behaviour is unchanged: the same extensions are reported as created, deleted, and updated, in the same order. uid was already used as the identity key, so a Map/Set keyed on it preserves the original semantics exactly.

Expected impact: reload-time diffing drops from quadratic to linear. Negligible for a handful of extensions, but it removes a scaling cliff on the hottest path of app dev for apps with many extensions.

How to manually test your changes?

shopify app dev

Then edit an extension's .toml (to trigger an update), add a new extension folder, and delete one. Confirm the dev server reports the created, updated, and deleted extensions exactly as before.

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes
  • I've considered analytics changes to measure impact
  • The change is user-facing — I've identified the correct bump type (patch for bug fixes · minor for new features · major for breaking changes) and added a changeset with pnpm changeset add

appDiff runs on every app reload during `shopify app dev`, so it executes
on each file change. It scanned the opposite extension array once per
extension, making it O(n²) in the number of extensions.

Index the old extensions by uid in a Map and the new uids in a Set so
created/deleted/updated detection is O(n) with O(1) lookups. Behaviour is
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants