Skip to content

feat: support TanStack Query v5 - #1

Merged
EliottGand merged 3 commits into
mainfrom
feat/support-tanstack-query-v5
Sep 21, 2026
Merged

EliottGand merged 3 commits into
mainfrom
feat/support-tanstack-query-v5

Conversation

@EliottGand

@EliottGand EliottGand commented Sep 21, 2026 •

Copy link
Copy Markdown
Contributor

What changed

  • package.json: peerDependencies["@tanstack/query-core"] from "~4" to ">=4 <6"
  • A real test suite (vitest), run against both majors, plus a test script
  • .github/workflows/ci.yml: typecheck + build + tests, matrixed over query-core 4 and 5
  • example/: a small Expo app that makes the detection visible on a device
  • README.md: one sentence stating both supported majors

No source change was needed. WaterfallQueryDetector.getPendingQueries() already matches both "pending" (v5) and "loading" (v4). The peer range was the only thing stopping v5 apps from installing the package.

Proof

1. Automated tests, both majors

yarn test runs the same suite twice through two vitest projects. query-core-v5 uses the installed v5; query-core-v4 resolves @tanstack/query-core to a npm:@tanstack/query-core@^4 alias dev dependency, so the library source under test really imports v4.

The tests drive an actual QueryClient (the query cache is not mocked) and assert on the payload the detector hands to console.warn, not merely that it did not throw:

  • two sequential queries produce exactly one waterfall, ["first"] --> ["second"]
  • two parallel queries produce none
  • a whitelisted pair produces none
  • a whitelist only silences the exact pair, not the rest of the chain
  • a three-query chain produces both links, in order
  • the returned unsubscribe handle stops detection
  • a query that settles alone is not treated as a waterfall source
$ yarn test
 ✓ |query-core-v4| src/__tests__/detectQueryWaterfalls.test.ts (7 tests) 143ms
 ✓ |query-core-v5| src/__tests__/detectQueryWaterfalls.test.ts (7 tests) 141ms

 Test Files  2 passed (2)
      Tests  14 passed (14)

The suite is a real gate, not a smoke test: temporarily reducing the status predicate to ["pending"] (dropping v4's loading) turns 4 of the 7 v4 tests red while v5 stays green.

2. CI

.github/workflows/ci.yml runs yarn install --immutable, yarn typecheck, yarn build and the suite, with one job per major. Both jobs are green on this branch.

3. On-device E2E with @tanstack/react-query v5

example/ is an Expo Go app on @tanstack/react-query@5.103.2, consuming this repo's built dist/ through file:.. (metro is configured so the library resolves the app's query-core, not its own). It taps console.warn, keeps the lines the detector actually emits and renders them on screen.

Run on an iPhone 17 Pro simulator, iOS 26.4, driven end to end:

  • start state: Detected waterfalls: 0, "No waterfall detected yet"
  • tap Run 2 SEQUENTIAL queries (["user",1], then ["posts-of-user",1] once the first resolves): the list shows ["user",1] --> ["posts-of-user",1], count 1
  • tap Run 2 PARALLEL queries (["profile",2] and ["settings",2] at once): count stays 1, nothing added

The Metro log for the whole session contains exactly one Detected query waterfalls warning.

Still not proven

  • Only v5.103.2 / v5.36.0 and v4.44.0 were exercised, not every release in the >=4 <6 range.
  • The device run is iOS only; the library is pure JS, but Android was not run.
  • Unrelated pre-existing issue, not touched here: dist/index.mjs emits import ... from "lodash/differenceBy" with no extension, which plain Node ESM refuses to resolve (ERR_MODULE_NOT_FOUND). Bundlers (Metro, webpack, vite) resolve it fine and the CJS build is unaffected, so normal usage is not impacted. Worth a separate fix if you want the ESM build to be Node-loadable.

Release

No version bump here, the release is left to you.

🤖 Generated with Claude Code

Eliott Gandiolle and others added 3 commits September 21, 2026 17:20
The detector was already v5-aware: `getPendingQueries()` matches both the
v5 `pending` and the v4 `loading` status, and every core API it uses
(`matchQuery`, `notifyManager.batchCalls`, `QueryCache.subscribe`,
`queryCache.findAll({ predicate })`) is unchanged in v5. Only the
peerDependency range `~4` blocked v5 apps from installing the package.

Widen it to `>=4 <6` and note both supported majors in the README.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add vitest (natural fit with the existing tsup/esbuild stack, no extra
transform config) and run the same behavioural suite against both majors
via two vitest projects: `query-core-v5` uses the installed v5, and
`query-core-v4` aliases `@tanstack/query-core` to a
`npm:@tanstack/query-core@^4` dev dependency.

The tests drive an actual QueryClient (no mocks of the query cache) and
assert on the warning payload: sequential queries, parallel queries,
whitelisting, a three-query chain, and the unsubscribe handle.

Add a GitHub Actions workflow running typecheck, build and the suite,
matrixed over query-core 4 and 5.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A small Expo Go app (react-query v5) consuming the library through
`file:..`. It taps `console.warn`, keeps the lines the detector really
emits, and renders them, so the detection is visible on a device: one
button fires two sequential dependent queries, the other two parallel
ones.

Run on an iPhone 17 Pro simulator (iOS 26.4): the sequential button adds
`["user",1] --> ["posts-of-user",1]` to the list, the parallel button
adds nothing.

Exclude the example from the root tsconfig, it is its own project.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@EliottGand
EliottGand merged commit 6e4ef55 into main Sep 21, 2026
2 checks passed
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.

1 participant