Skip to content

Commit a0e5024

Browse files
authored
Merge pull request #268 from gadget-inc/optional-websocket
Support weird shopify extensions context
2 parents fe596df + 07ea893 commit a0e5024

File tree

6 files changed

+87
-102
lines changed

6 files changed

+87
-102
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @jest-environment ./spec/remote-ui-environment.ts
3+
*/
4+
jest.mock("isomorphic-ws", () => null); // mimic browser environment for remote-ui where the websocket global is not available
5+
import { GadgetConnection } from "../src/GadgetConnection.js";
6+
import { GadgetConnectionSharedSuite } from "./GadgetConnection-suite.js";
7+
8+
describe("GadgetConnection in remote-ui", () => {
9+
GadgetConnectionSharedSuite();
10+
11+
test("throws an error concerning missing websocket constructor as it is not available", async () => {
12+
const connection = new GadgetConnection({ endpoint: "https://someapp.gadget.app" });
13+
await expect(async () => await connection.transaction({}, async () => true)).rejects.toThrowErrorMatchingInlineSnapshot(
14+
`"Can't use this GadgetClient for this subscription-based operation as there's no global WebSocket implementation available. Please pass one as the \`websocketImplementation\` option to the GadgetClient constructor."`
15+
);
16+
});
17+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { TestEnvironment } from "jest-environment-node";
2+
3+
/**
4+
* Implements an environment with only the stuff present in a remote-ui environment
5+
* What that is isn't actually documented anywhere as best I can tell, but we do know there is no WebSocket global
6+
* See https://github.com/Shopify/remote-ui */
7+
export default class RemoteUIEnvironment extends TestEnvironment {
8+
async setup() {
9+
await super.setup();
10+
delete (this.global as any).WebSocket;
11+
}
12+
}

packages/api-client-core/src/GadgetConnection.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,14 @@ export class GadgetConnection {
7373
private endpoint: string;
7474
private subscriptionClientOptions?: SubscriptionClientOptions;
7575
private websocketsEndpoint: string;
76-
private websocketImplementation: any;
76+
private websocketImplementation?: WebSocket;
7777
private _fetchImplementation: typeof globalThis.fetch;
7878
private environment: "Development" | "Production";
7979
private exchanges: Required<Exchanges>;
8080

8181
// the base client using HTTP requests that non-transactional operations will use
8282
private baseClient: Client;
83-
private baseSubscriptionClient: SubscriptionClient;
83+
private baseSubscriptionClient?: SubscriptionClient;
8484

8585
// the transactional websocket client that will be used inside a transaction block
8686
private currentTransaction: GadgetTransaction | null = null;
@@ -117,8 +117,6 @@ export class GadgetConnection {
117117

118118
this.setAuthenticationMode(options.authenticationMode);
119119

120-
// the base client for subscriptions is lazy so we don't open unnecessary connections to the backend, and it reconnects to deal with network issues
121-
this.baseSubscriptionClient = this.newSubscriptionClient({ lazy: true });
122120
this.baseClient = this.newBaseClient();
123121
}
124122

@@ -266,7 +264,7 @@ export class GadgetConnection {
266264
};
267265

268266
close() {
269-
this.disposeClient(this.baseSubscriptionClient);
267+
if (this.baseSubscriptionClient) this.disposeClient(this.baseSubscriptionClient);
270268
if (this.currentTransaction) {
271269
this.currentTransaction.close();
272270
}
@@ -352,7 +350,8 @@ export class GadgetConnection {
352350
return {
353351
subscribe: (sink) => {
354352
const input = { ...request, query: request.query || "" };
355-
const dispose = this.baseSubscriptionClient.subscribe(input, sink as Sink<ExecutionResult>);
353+
354+
const dispose = this.getBaseSubscriptionClient().subscribe(input, sink as Sink<ExecutionResult>);
356355
return {
357356
unsubscribe: dispose,
358357
};
@@ -374,6 +373,12 @@ export class GadgetConnection {
374373
}
375374

376375
private newSubscriptionClient(overrides: GadgetSubscriptionClientOptions) {
376+
if (!this.websocketImplementation) {
377+
throw new Error(
378+
"Can't use this GadgetClient for this subscription-based operation as there's no global WebSocket implementation available. Please pass one as the `websocketImplementation` option to the GadgetClient constructor."
379+
);
380+
}
381+
377382
let url = this.websocketsEndpoint;
378383
if (overrides?.urlParams) {
379384
const params = new URLSearchParams();
@@ -503,6 +508,13 @@ export class GadgetConnection {
503508
maybePromise.catch((err: any) => console.error(`Error closing SubscriptionClient: ${err.message}`));
504509
}
505510
}
511+
512+
private getBaseSubscriptionClient() {
513+
if (!this.baseSubscriptionClient) {
514+
this.baseSubscriptionClient = this.newSubscriptionClient({ lazy: true });
515+
}
516+
return this.baseSubscriptionClient;
517+
}
506518
}
507519

508520
function processMaybeRelativeInput(input: RequestInfo | URL, endpoint: string): RequestInfo | URL {

packages/react/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
},
3030
"dependencies": {
3131
"@gadgetinc/api-client-core": "^0.15.0",
32-
"deep-equal": "^2.2.0",
32+
"react-fast-compare": "^3.2.2",
3333
"urql": "^4.0.4"
3434
},
3535
"resolutions": {
@@ -39,7 +39,6 @@
3939
"@gadgetinc/api-client-core": "workspace:*",
4040
"@testing-library/jest-dom": "^5.16.5",
4141
"@testing-library/react": "^13.4.0",
42-
"@types/deep-equal": "^1.0.1",
4342
"@types/jest": "^29.5.2",
4443
"@types/lodash": "^4.14.191",
4544
"@types/node": "^18.0.0",

packages/react/src/useStructuralMemo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import deepEqual from "deep-equal";
21
import { useRef } from "react";
2+
import deepEqual from "react-fast-compare";
33

44
/**
55
* Memoize and ensure a stable identity on a given value as long as it remains the same, structurally.

0 commit comments

Comments
 (0)