chore(deps): upgrade Apollo Client 3→4 (#9376) - #9544
Open
mikeallisonJS wants to merge 2 commits into
Open
Conversation
Takes the client half of the GraphQL-core family on #9376's upgrade roadmap. `graphql` stays on 16: the federation stack caps it there (`@apollo/subgraph` peers `^16.5.0`, `@apollo/server` `^16.11.0`, `@graphql-hive/gateway` `^15.9.0 || ^16.9.0`), so 16→17 is blocked until those move. Apollo's official codemod handled the mechanical part — entry points (`@apollo/client/react`, `@apollo/client/testing/react`), namespaced types, class-based links and the `ApolloClient` constructor options. The rest was done by hand: - Error handling: `ApolloError` is gone. GraphQL errors now arrive as `CombinedGraphQLErrors`, and `LinkError.is()` replaces the old `networkError` check for transport failures. - Removed hook options: `useQuery`/`useLazyQuery` lost `onCompleted` and `onError`; those call sites now read the result. Lazy queries that were executed from an effect became `useQuery` + `skipToken`, and `useLazyQuery` variables moved to the execute function. - Typing: dropped the removed `ApolloCache<T>` generic, narrowed wrapper hooks' `TStates` so consumers don't see partial data, and guarded the now-optional `data` on server-side `client.query` calls. Two links had to be vendored. `@adobe/apollo-link-mutation-queue` returns zen-observables, which v4 pipes through rxjs operators; `apollo-link-debounce` ships an ES5 build whose `_super.call(this)` shim can't extend v4's real `ApolloLink` class. Both are ported in-repo with behaviour unchanged, and the packages (plus the now-unused `zen-observable-ts`) are dropped. Test setups pin `MockLink.defaultOptions = { delay: 0 }` to keep v3's immediate mock responses; specs that mocked hooks off `@apollo/client` now mock `@apollo/client/react`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Regenerate the lockfile. The three dropped packages were removed from package.json after the last install, so their `importers` entries lingered and `pnpm install --frozen-lockfile` would have failed. - Cover both vendored links. `MutationQueueLink` had no test at all; `DebounceLink` was only exercised indirectly through editor specs. Both specs fail against a deliberately broken implementation. - Give `useUserInvitesLazyQuery` a `useUserInvitesQuery` sibling so AccessDialog reads invites through `src/libs/` rather than importing the raw document, per the app's convention guide. - Refresh apps/journeys-admin/AGENTS.md: the Apollo entry-point map and the note that the debounce and mutation-queue links now live in-repo. - Explain why useCustomDomainsQuery lists its options rather than taking `useQuery.Options` — a wide options type puts `partial` in the result's data states and hands callers DeepPartial data. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
|
Important Review skippedToo many files! This PR contains 1124 files, which is 1024 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1124)
You can disable this status message by setting the |
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.
Delivers the
@apollo/clienthalf of the GraphQL core family from the upgrade roadmap in #9376. Twelfth roadmap family to land, after ESLint (#9514), MUI (#9445), Vitest (#9484), Nx (#9415) and the rest.graphql16 → 17 is blocked, not skippedThe roadmap states the family as "
graphql(16 → 17) and@apollo/client(3 → 4, major client rewrite)". Only the client half is possible today — the federation stack capsgraphqlat 16:graphqlpeer@apollo/subgraph^16.5.0@apollo/server^16.11.0@graphql-hive/gateway^15.9.0 || ^16.9.0@apollo/client^16.0.0 || ^17.0.0← the only one readySo
graphqlstays on 16 and the 16→17 bump waits on those three moving. Worth folding back into the issue.One roadmap line resolves as a non-finding: "chase the stray transitive
graphql@4.8.0resolution surfaced in the lockfile". The only4.8.0in the lockfile is@octokit/graphql@4.8.0— an unrelated package, not a straygraphqlresolution.What moved
@apollo/client@apollo/client-integration-nextjs@apollo/client@^4)rxjsRemoved:
@adobe/apollo-link-mutation-queue,apollo-link-debounce,zen-observable-ts— see below.Codemod, then the parts it can't do
@apollo/client-codemod-migrate-3-to-4handled the mechanical sweep across ~1,100 files: entry points (@apollo/client/react,@apollo/client/testing/react,@apollo/client/link/*), types moved into namespaces (ApolloLink.Result,useQuery.Options,MockLink.MockedResponse), link creators → classes, and theApolloClientconstructor reshuffle. Apollo's own docs say it gets you ~90% of the way; the remainder was diagnosed case by case.Error handling —
ApolloErroris goneGraphQL errors now arrive as
CombinedGraphQLErrors; everything else is passed through unwrapped. The interesting part waserror.networkError, which had no obvious replacement.LinkError.is()is the exact one: Apollo registers errors inregisterLinkErrorfrom acatchErroron the raw link observable, beforeCombinedGraphQLErrorsis constructed downstream — so it means precisely "AC3 would have setnetworkError". Verified against the v4 source rather than inferred, which is why the snackbar branches keep their original meaning instead of collapsing into "any error".Removed hook options
useQuery/useLazyQuerylostonCompletedandonErroroutright. Each site now reads the result instead. Two shared hooks keep their public contract by mirroring the callbacks internally (useJourneyAnalyticsQuery,useJourneyAiTranslateSubscription) so their callers were untouched.useLazyQueryalso lost hook-levelvariables, and executing one outside an event handler now throws. Lazy queries that were fired from an effect (AccessDialog, LocalDetails) becameuseQuery+skipToken— which is what Apollo's guide recommends, and drops a render-cycle round trip.Three behaviour changes that only surface at runtime
Found by running the suites, not by reading the diff:
next, then complete.onCompletenow fires after a failure, where v3 terminated. Callers readonCompleteas "translation succeeded" and were switching teams on error. Gated once in the shared subscription hook rather than at six call sites.onErroris supplied. v3 resolved. Threeawait mutate({ onError })call sites were leaking unhandled rejections.MockLinkgained a random 20–50 ms delay. The suite was written against v3's immediate responses; pinned back to{ delay: 0 }in the ten test setups, as the migration guide suggests.Two links had to be vendored
Both are incompatible with v4 in ways no version bump fixes, so they are ported in-repo under
apps/journeys-admin/src/libs/apolloClient/with behaviour unchanged:@adobe/apollo-link-mutation-queuereturnszen-observableinstances. v4'sQueryManagercalls.pipe()on link results, which zen-observable does not have.apollo-link-debounceships an ES5 build that subclassesApolloLinkvia a_super.call(this)shim. v4'sApolloLinkis a real class, so it throws "Class constructor ApolloLink cannot be invoked without 'new'" the moment the link is constructed.Both are now covered by specs (there were none before — the debounce link was only exercised indirectly through editor specs). Each spec was checked against a deliberately broken implementation to confirm it fails.
zen-observable-tswent with them; nothing imported it once the Adobe link was gone.Typing fallout
ApolloCache<T>lost its generic — dropped at 10 sites.ApolloCache.extract()now returnsunknown; cast where the result is written into page props. InuseBlockDeleteCommandthis had been masking a real gap — the editor's step blocks carry nox/y, butblockRestore's response type requires them, so the optimistic response now reads the coordinates back off the cache.useQuery.Optionswere leavingreturnPartialDataunresolved, which putpartialin the union and handed every callerDeepPartialdata. TheirTStatesare now narrowed, so consumers keep complete data.client.querytypesdataas optional under the default error policy. Call sites with inferred generics stateerrorPolicy: 'none'(which is what they already relied on); the rest narrow explicitly.Sharper variable typing in arclight surfaced two genuine latent bugs: a
selectvariable the query never declared, and fourc.req.param()values passed as requiredID!while typedstring | undefined.Verification
nx testfails on even whenvitest runpasses.pnpm install --frozen-lockfileverified.