apollographql/apollo-link

apollo-link-ws loads backend modules when using it in the browser

Opened this issue · 1 comments

Expected Behavior
apollo-link-ws package does not crash whole web app.

Actual Behavior
apollo-link-ws crashes app due to backed packages being required.

A simple reproduction
Use the mentioned package's export "WebSocketLink" in frontend code.

Monkey patch for front end, will break backend ofcourse
In node_modules/apollo-link-ws/lib/webSocketLink.js change:
var subscriptions_transport_ws_1 = require("subscriptions-transport-ws");
to:
var subscriptions_transport_ws_1 = require("subscriptions-transport-ws/browser/client.js");

Version
apollo-link-ws 1.0.19

How i eventually fixed it

I just created a file with this content (fetched from the apollo-link-ws repo and removed some types and updated the import path for 'subscriptions-transport-ws', https://raw.githubusercontent.com/apollographql/apollo-link/master/packages/apollo-link-ws/src/webSocketLink.ts)

import { ApolloLink, Operation, FetchResult, Observable } from 'apollo-link'

import { SubscriptionClient } from 'subscriptions-transport-ws/dist/client'

export class WebSocketLink extends ApolloLink {
  private subscriptionClient

  constructor(paramsOrClient) {
    super()

    if (paramsOrClient instanceof SubscriptionClient) {
      this.subscriptionClient = paramsOrClient
    } else {
      this.subscriptionClient = new SubscriptionClient(
        paramsOrClient.uri,
        paramsOrClient.options,
        paramsOrClient.webSocketImpl,
      )
    }
  }

  public request(operation: Operation): Observable<FetchResult> | null {
    return this.subscriptionClient.request(operation) as Observable<FetchResult>
  }
}

Encountered this as well. I can provide another potential solution and more context.

(Potential) Alternate Solution - Webpack
Check your webpack config's resolve.mainFields. Reference

When the target property is set to webworker, web, or left unspecified:

module.exports = {
  resolve: {
    mainFields: ['browser', 'module', 'main']
  }
};

When referenced against subscriptions-transport-ws, webpack should use dist/client.js.
In my case, the webpack config defined a different order in which main was preferred. Changing that resolved the issue.

Background

Tracked down this line causing errors: import { WebSocketLink } from 'apollo-link-ws'.
My terminal has a bunch of different errors in the format of:

ERROR in ./node_modules/graphql/index.mjs 42:0-48:205
    Can't reexport the named export 'visitInParallel' from non EcmaScript module (only default export is available)

and then in the browser:

Error: Cannot find module 'tls' at webpackMissingModule

I tried the above solution, rewriting the class and importing from 'subscriptions-transport-ws/dist/client' directly, and it works. But I was unsatisfied.

The reason I was unsatisfied is because I have other implementations on top of both create react app and nextjs that import apollo-link-ws the same way without issue. I spent a while debugging before noticing the package.json's browser property and checking my webpack config.