結論: WebSocketLinkはサーバーサイドでは使えない
- SSRが問題
- WebSocketLinkはブラウザで動作させて上げないといけない
- WebSocketLinkがSSR時にサーバー側でエラーを起こしている
-
process.browser
で判定してブラウザでのみWebSocketLinkを使う
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
const wsLink = process.browser ? new WebSocketLink({
uri: "ws://localhost:8080/v1/graphql",
options: {
reconnect: true,
connectionParams: {
headers: {
},
},
}
}) : undefined;
const client = new ApolloClient({
link: wsLink,
cache: new InMemoryCache(),
});
前提
Hasura, Apollo, React, SSR(サーバーサイドレンダリング)
でGraphQLのSubscriptionsでリアルタイム更新をしたくてwebSocketを使った。
エラー内容
Error: Unable to find native implementation, or alternative implementation for WebSocket!
解決
この実装ではエラーが出ます。
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
const wsLink = new WebSocketLink({
uri: "ws://localhost:8080/v1/graphql",
options: {
reconnect: true,
connectionParams: {
headers: {
},
},
},
});
const client = new ApolloClient({
link: wsLink,
cache: new InMemoryCache(),
});
わるかったところ
結局SSRでサーバーサイドでのレンダリングをしている時に問題が起こっているようでした。
どうやらWebSocketはブラウザ側で動作させて上げないといけないらしい。
node.jsにもwsなるプラグインがあったので色々やれば動作するのかも知れないが
回避
process.browser
でブラウザ動作かを判定して三項演算子でtrueならWebSocketLinkのインスタンスを返す。
falseなら返さないとしたいのでundefined
を返す
undefinedがいいかは分からなかったが、もっといい案があれば教えて下さい。
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { WebSocketLink } from "@apollo/client/link/ws";
const wsLink = process.browser ? new WebSocketLink({
uri: "ws://localhost:8080/v1/graphql",
options: {
reconnect: true,
connectionParams: {
headers: {
},
},
}
}) : undefined;
const client = new ApolloClient({
link: wsLink,
cache: new InMemoryCache(),
});
参考
GitHub
https://github.com/apollographql/subscriptions-transport-ws/issues/333#issuecomment-359261024
Hasura Subscription
https://hasura.io/learn/graphql/react/subscriptions/1-subscription/