Skip to content

Commit e0b4862

Browse files
0.10.0 (1) - Throw error when passing arguments into getClient. (#203)
* Throw error when passing arguments into `getClient`. * Update packages/client-react-streaming/src/registerApolloClient.tsx Co-authored-by: Jerel Miller <[email protected]> * Update packages/client-react-streaming/src/registerApolloClient.tsx * add unit tests for `registerApolloClient` * add test for call with parameters --------- Co-authored-by: Jerel Miller <[email protected]>
1 parent fd40453 commit e0b4862

File tree

4 files changed

+173
-3
lines changed

4 files changed

+173
-3
lines changed

packages/client-react-streaming/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
"publint": "0.2.7",
135135
"react": "18.3.0-canary-60a927d04-20240113",
136136
"react-error-boundary": "4.0.13",
137+
"react-server-dom-webpack": "18.3.0-canary-60a927d04-20240113",
137138
"rimraf": "5.0.5",
138139
"superjson": "1.13.3",
139140
"ts-node": "10.9.2",
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { it } from "node:test";
2+
import assert from "node:assert";
3+
import { runInConditions } from "./util/runInConditions.js";
4+
import { Writable } from "node:stream";
5+
6+
runInConditions("react-server");
7+
8+
const { registerApolloClient, ApolloClient, InMemoryCache } = await import(
9+
"#bundled"
10+
);
11+
12+
type ReactServer = {
13+
renderToPipeableStream(
14+
model: React.ReactNode,
15+
webpackMap: unknown,
16+
options?: {
17+
environmentName?: string;
18+
onError?: (error: any) => void;
19+
onPostpone?: (reason: string) => void;
20+
identifierPrefix?: string;
21+
}
22+
): {
23+
abort(reason: any): void;
24+
pipe<T extends Writable>(destination: T): T;
25+
};
26+
};
27+
28+
const { renderToPipeableStream } = (await import(
29+
// @ts-expect-error close enough
30+
"react-server-dom-webpack/server"
31+
)) as ReactServer;
32+
const React = await import("react");
33+
34+
function drain(stream: ReturnType<typeof renderToPipeableStream>) {
35+
let result = "";
36+
return new Promise<string>((resolve) => {
37+
stream.pipe(
38+
new Writable({
39+
write(chunk, _encoding, callback) {
40+
result += chunk.toString();
41+
callback();
42+
},
43+
final(callback) {
44+
resolve(result);
45+
callback();
46+
},
47+
})
48+
);
49+
});
50+
}
51+
52+
function makeClient() {
53+
return new ApolloClient({
54+
cache: new InMemoryCache(),
55+
connectToDevTools: false,
56+
});
57+
}
58+
59+
it("calling `getClient` outside of a React render creates a new instance every time", () => {
60+
const { getClient } = registerApolloClient(makeClient);
61+
62+
const client1 = getClient();
63+
const client2 = getClient();
64+
assert.notStrictEqual(client1, client2);
65+
});
66+
67+
it("calling `getClient` twice during the same React render will return the same instance", async () => {
68+
const { getClient } = registerApolloClient(makeClient);
69+
70+
const clients: any[] = [];
71+
function App() {
72+
clients.push(getClient());
73+
clients.push(getClient());
74+
return <div></div>;
75+
}
76+
77+
const stream = renderToPipeableStream(React.createElement(App), {});
78+
await drain(stream);
79+
80+
assert.equal(clients.length, 2);
81+
assert.ok(clients[0] instanceof ApolloClient);
82+
assert.strictEqual(clients[0], clients[1]);
83+
});
84+
85+
it("calling `getClient` twice during different React renders will return different instances", async () => {
86+
const { getClient } = registerApolloClient(makeClient);
87+
88+
const clients: any[] = [];
89+
function App() {
90+
clients.push(getClient());
91+
return <div></div>;
92+
}
93+
94+
{
95+
const stream = renderToPipeableStream(React.createElement(App), {});
96+
await drain(stream);
97+
}
98+
{
99+
const stream = renderToPipeableStream(React.createElement(App), {});
100+
await drain(stream);
101+
}
102+
103+
assert.equal(clients.length, 2);
104+
assert.ok(clients[0] instanceof ApolloClient);
105+
assert.notStrictEqual(clients[0], clients[1]);
106+
});
107+
108+
it("calling `getClient` with parameters results in an error", async () => {
109+
const { getClient } = registerApolloClient(makeClient);
110+
111+
function App() {
112+
// @ts-expect-error yeah this is a bad idea, that's why we do it in a test
113+
getClient("argument");
114+
return <div></div>;
115+
}
116+
117+
let error: undefined | Error;
118+
const stream = renderToPipeableStream(
119+
React.createElement(App),
120+
{},
121+
{
122+
onError(e) {
123+
error = e;
124+
},
125+
}
126+
);
127+
await drain(stream);
128+
assert.ok(
129+
/You cannot pass arguments into `getClient`./.test(error?.message || "")
130+
);
131+
});

packages/client-react-streaming/src/registerApolloClient.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,20 @@ export function registerApolloClient(makeClient: () => ApolloClient<any>): {
5050
export function registerApolloClient(
5151
makeClient: (() => Promise<ApolloClient<any>>) | (() => ApolloClient<any>)
5252
) {
53-
const getClient = cache(makeClient);
53+
function wrappedMakeClient() {
54+
if (arguments.length) {
55+
throw new Error(
56+
`
57+
You cannot pass arguments into \`getClient\`.
58+
Passing arguments to \`getClient\` returns a different instance
59+
of Apollo Client each time it is called with different arguments, potentially
60+
resulting in duplicate requests and a non-functional cache.
61+
`.trim()
62+
);
63+
}
64+
return makeClient();
65+
}
66+
const getClient = cache(wrappedMakeClient);
5467
return {
5568
getClient,
5669
};

yarn.lock

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ __metadata:
7171
publint: "npm:0.2.7"
7272
react: "npm:18.3.0-canary-60a927d04-20240113"
7373
react-error-boundary: "npm:4.0.13"
74+
react-server-dom-webpack: "npm:18.3.0-canary-60a927d04-20240113"
7475
rimraf: "npm:5.0.5"
7576
superjson: "npm:1.13.3"
7677
ts-invariant: "npm:^0.10.3"
@@ -5763,14 +5764,23 @@ __metadata:
57635764
languageName: node
57645765
linkType: hard
57655766

5767+
"acorn-loose@npm:^8.3.0":
5768+
version: 8.4.0
5769+
resolution: "acorn-loose@npm:8.4.0"
5770+
dependencies:
5771+
acorn: "npm:^8.11.0"
5772+
checksum: 10/a005b2bee62e2575963b311ab7c45701062115a62e4286162498b1b198a6f884ceea186592ce41a27d5f382a5b640f1dffb37dd0e6e7848a74dd36e4b0a55105
5773+
languageName: node
5774+
linkType: hard
5775+
57665776
"acorn-walk@npm:^8.1.1, acorn-walk@npm:^8.3.2":
57675777
version: 8.3.2
57685778
resolution: "acorn-walk@npm:8.3.2"
57695779
checksum: 10/57dbe2fd8cf744f562431775741c5c087196cd7a65ce4ccb3f3981cdfad25cd24ad2bad404997b88464ac01e789a0a61e5e355b2a84876f13deef39fb39686ca
57705780
languageName: node
57715781
linkType: hard
57725782

5773-
"acorn@npm:^8.10.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0":
5783+
"acorn@npm:^8.10.0, acorn@npm:^8.11.0, acorn@npm:^8.7.1, acorn@npm:^8.8.2, acorn@npm:^8.9.0":
57745784
version: 8.11.3
57755785
resolution: "acorn@npm:8.11.3"
57765786
bin:
@@ -11832,7 +11842,7 @@ __metadata:
1183211842
languageName: node
1183311843
linkType: hard
1183411844

11835-
"neo-async@npm:^2.6.2":
11845+
"neo-async@npm:^2.6.1, neo-async@npm:^2.6.2":
1183611846
version: 2.6.2
1183711847
resolution: "neo-async@npm:2.6.2"
1183811848
checksum: 10/1a7948fea86f2b33ec766bc899c88796a51ba76a4afc9026764aedc6e7cde692a09067031e4a1bf6db4f978ccd99e7f5b6c03fe47ad9865c3d4f99050d67e002
@@ -13154,6 +13164,21 @@ __metadata:
1315413164
languageName: node
1315513165
linkType: hard
1315613166

13167+
"react-server-dom-webpack@npm:18.3.0-canary-60a927d04-20240113":
13168+
version: 18.3.0-canary-60a927d04-20240113
13169+
resolution: "react-server-dom-webpack@npm:18.3.0-canary-60a927d04-20240113"
13170+
dependencies:
13171+
acorn-loose: "npm:^8.3.0"
13172+
loose-envify: "npm:^1.1.0"
13173+
neo-async: "npm:^2.6.1"
13174+
peerDependencies:
13175+
react: 18.3.0-canary-60a927d04-20240113
13176+
react-dom: 18.3.0-canary-60a927d04-20240113
13177+
webpack: ^5.59.0
13178+
checksum: 10/b52ca5befe8e4470a82b79602d10f9949b90d3a4fd90f2067774ad90b311ecb84bd767ec05e8c64df58b12daf37f8aa09349c41c321d13d062e669d04a91507f
13179+
languageName: node
13180+
linkType: hard
13181+
1315713182
"react-style-singleton@npm:^2.2.1":
1315813183
version: 2.2.1
1315913184
resolution: "react-style-singleton@npm:2.2.1"

0 commit comments

Comments
 (0)