reactjsgraphqlnext.jsurql

Nextjs urql subscription exchange import problem


i can't get urql subscriptions to work with NextJS because of imports problem.

Basically i'm using this graphql-ws lib that is recommended in urql docs, that needs ws implementation library (eg: 'ws'). And when i import WebSocket from 'ws' i get this error: Module not found: Can't resolve 'net'

import { createClient, defaultExchanges, subscriptionExchange, Client } from 'urql';
import { createClient as createWSClient } from 'graphql-ws';
import WebSocket from 'ws'; // <-- This causes the error

export const createUrqlClient = (): Client => {
  const wsClient = createWSClient({
    url: 'ws://xxx/graphql',
    webSocketImpl: WebSocket,
  });

  const client = createClient({
    url: 'http://xxx/graphql',
    exchanges: [
      ...defaultExchanges,
      subscriptionExchange({
        forwardSubscription: operation => ({
          subscribe: sink => ({
            unsubscribe: wsClient.subscribe(operation, sink),
          }),
        }),
      }),
    ],
  });

  return client;
};

I tried nextjs dynamic import and both of these didn't work as well:

const WebSocket = dynamic(() => import('ws'), { ssr: false });
const WebSocket = dynamic(() => import('ws').then(module => module.default), { ssr: false });

I also tried to alter webpack config in next.config.js to not bundle these libs at all:

webpack: (config, { isServer }) => {
  if (!isServer) {
    config.resolve.fallback = {
      child_process: false,
      process: false,
      fs: false,
      util: false,
      http: false,
      https: false,
      tls: false,
      net: false,
      crypto: false,
      path: false,
      os: false,
      stream: false,
      zlib: false,
      querystring: false,
      events: false,
      'utf-8-validate': false,
      bufferutil: false,
    };
  }
  return config;
},

but then i get these errors:

./node_modules/ws/lib/validation.js
Module not found: Can't resolve 'utf-8-validate' in '/home/danko/app/node_modules/ws/lib'
warn  - ./node_modules/ws/lib/buffer-util.js
Module not found: Can't resolve 'bufferutil' in '/home/danko/app/node_modules/ws/lib'

if i add 'utf-8-validate': false and bufferutil: false to the cfg as well i get this err:

TypeError: Class extends value undefined is not a constructor or null

So basically nothing works properly then as you can see...

How hard can this be, i can't be the only person that uses urql subscriptions with nextjs, hope somebody can help me with this. Thanks!


Solution

  • Basically as i thought, impl was not needed because native html5 websocket can be used, problem was trash nextjs with it's server side thing.

    I pretty much don't use that exchange when typeof window !== 'undefined' this is the working code:

    import { createClient, dedupExchange, cacheExchange, subscriptionExchange, Client, Exchange } from 'urql';
    import { multipartFetchExchange } from '@urql/exchange-multipart-fetch';
    import { createClient as createWSClient } from 'graphql-ws';
    
    export const createUrqlClient = (): Client => {
      const graphqlEndpoint = process.env!.NEXT_PUBLIC_GRAPHQL_ENDPOINT as string;
      const graphqlWebsocketEndpoint = process.env!.NEXT_PUBLIC_GRAPHQL_WS_ENDPOINT as string;
    
      let exchanges: Exchange[] | undefined = [dedupExchange, cacheExchange, multipartFetchExchange];
    
      if (typeof window !== 'undefined') {
        const wsClient = createWSClient({
          url: graphqlWebsocketEndpoint,
        });
    
        const subExchange = subscriptionExchange({
          forwardSubscription: operation => ({
            subscribe: sink => ({
              unsubscribe: wsClient.subscribe(operation, sink),
            }),
          }),
        });
    
        exchanges.push(subExchange);
      }
    
      const client = createClient({
        url: graphqlEndpoint,
        requestPolicy: 'cache-and-network',
        exchanges,
        fetchOptions: () => ({
          credentials: 'include',
        }),
      });
    
      return client;
    };