Cannot read properties of undefined (reading 'FIELD') when bumping @apollo/client to 3.8.x

275 views Asked by At

I have a particular feature where I require to implement a second graphql client (using @apollo/client) that uses the old ws protocol for subscriptions - the other graphql client uses the latest one.

This is a code snippet of a codesandbox link

import React, { useState } from "react";
import reactLogo from "./assets/react.svg";
import {
  ApolloClient,
  InMemoryCache,
  split,
  HttpLink,
  ApolloProvider,
  NormalizedCacheObject,
} from "@apollo/client";
import { getMainDefinition } from "@apollo/client/utilities";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { WebSocketLink } from "@apollo/client/link/ws";
import { createClient } from "graphql-ws";
import { SubscriptionClient } from "subscriptions-transport-ws";

import "./App.css";

export let graphQLClient: ApolloClient<NormalizedCacheObject>;
let clientWithOldWS: ApolloClient<NormalizedCacheObject>;

function createClientApollo() {
  if (graphQLClient && clientWithOldWS) {
    return null;
  }
  const wsLink = new GraphQLWsLink(
    createClient({
      url: `ws://127.0.0.1:12312/subscriptions`,
    }),
  );

  const httpLink = new HttpLink({
    uri: `http://127.0.0.1:12312/graphql`,
  });

  const splitLink = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === "OperationDefinition" &&
        definition.operation === "subscription"
      );
    },
    wsLink,
    httpLink,
  );

  graphQLClient = new ApolloClient({
    link: splitLink,
    cache: new InMemoryCache({ addTypename: false }),
    defaultOptions: {
      // Disable cache for both query and useQuery
      watchQuery: {
        fetchPolicy: "no-cache",
      },
      query: {
        fetchPolicy: "no-cache",
      },
      mutate: {
        fetchPolicy: "no-cache",
      },
    },
  });

  const url = `127.0.0.1:16123`;
  const wsLink2 = new WebSocketLink(
    new SubscriptionClient(`ws://${url}/graphql`, {
      reconnect: true,
    }),
  );

  const httpLink2 = new HttpLink({
    uri: `http://${url}/graphql`,
  });

  const splitLink2 = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === "OperationDefinition" &&
        definition.operation === "subscription"
      );
    },
    wsLink2,
    httpLink2,
  );

  clientWithOldWS = new ApolloClient({
    link: splitLink2,
    cache: new InMemoryCache({ addTypename: false }),
  });
}

function App() {
  const [count, setCount] = useState(0);
  createClientApollo();
  return (
    <ApolloProvider client={graphQLClient}>
      <div className="App">
         Loads
      </div>
    </ApolloProvider>
  );
}

export default App;

The general idea is to have one client with the latest version of the transport protocol for websockets and the other that connects to another server that uses the old graphql-ws websocket implementation.

If I use @apollo/client 3.7.17 it works as expected. If I bump to 3.8.x it does not. I'm running out of ideas on what to figure out.

Thoughts?

1

There are 1 answers

0
CanIHazCookieNow On BEST ANSWER

Issue resolved by changing the import order, moving the imports of graphql-ws and subscriptions-transport-ws before any @apollo import.

This is most likely a bundler issue and how it resolves imports - hence why graphql is undefined when the specific code runs.

Fixed codesandbox