GraphQLとReactとmeta、思うこと

ushironoko
·

全然まとめきらないし理解できてないことも多いので間違ってたら指摘していただいて結構です。

---

こんなことを思っていた。

そもそもの発端はGraphQL Foundationのメンバーからmetaの名前が消えたことだった。

GraphQLはそもそもFacebookが開発し、Relayというライブラリと共に一世を風靡、とまではいかなくとも一定の知名度とその有用性を知らしめたREST APIに変わる技術だ。

そのメンバーから開発元のmetaの名前が消えた。これはよく考えなくともすごいことが起こっている。つまりmetaはGraphQLを積極的に押すことはなくなったということだ。

その理由の裏に、(これは完全な妄想だが)Reactとの方向性のズレがあるような気がしている。

Reactは今サーバーコンポーネントの技術に全振りしている。サーバーコンポーネントとはその名の通りサーバー上で(も)実行されるコンポーネントで、実行結果をシリアライズしてクライアントに送ることができる。

これと組み合わせて使われるのがSSR Streamingという技術で、サーバーコンポーネント内でfetchが走る(Promiseが投げられる)と代替コンテンツを先にクライアントに返し、Promiseが解決されコンポネが準備できたタイミングで続けて本来出したかったコンテンツを返す、ということができる。

Nextでお馴染みのVercelと協力し、もはやReactのデフォルトはサーバーコンポーネントだと言わんばかりの状態まで来ている。

一方でこの技術とGraphQLは相性がそんなに良くないこともある(と自分は感じている)。

GraphQLはその特性上、グラフ構造を定義して1回のクエリで可能な限りデータを取得することを目指す。

RSC/Streaming SSRの例としてXを使うと、`/posts` でTLの情報を、`/trends` でトレンドの情報をそれぞれREST APIでfetchする時、サーバーコンポーネントで作っていると以下の流れになる。

  1. TLコンポネとトレンドコンポネでそれぞれfetchが走る

  2. それぞれの代替コンテンツが返る

  3. fetchが完了し、レンダリングできた方から順次コンテンツが返る

これをGraphQLでやると、グラフ構造で取得するためそもそもfetchは1回になる。TLコンポネとトレンドコンポネそれぞれでPromiseを投げるということができず、コンポーネント単位でのStreaming SSRもできないということになる。

Fragmentのようなクエリの断片化に対応できる仕組みもあるが、これは大元のuseQuery(に類するfetch client)がPromiseを投げるため子がそれぞれ待機するようなことができない…気がする。あたかもuseFragment(fragmentを取り出すフック)自体がデータフェッチをするかのように振る舞う必要がありそう。

結局ルートでまとめてクエリするという特性上(オーバー&アンダーフェッチの排除というのもある)、そのコンポネツリーをまるっとサスペンドすることになり、グラフをfragmentとして断片化したとしてもそれは変わらないのでSSR Streamingの恩恵が薄いのではないか?と思った。

この考えだとmetaがRSC/SSR Streamingにベットする以上GraphQLを使い続けるのは微妙というのもわかるので、そういうことなのかなと勝手に妄想している。

追記

自分はSchema Stitchingをまじめに考えないといけない程度の規模でGraphQLを使っている企業に所属しており、フロントエンドエンジニアとして割とGraphQLを使っているユーザーで、GraphQLのことを良い技術だと思っている方だ、という前提を書くのを忘れていた。

追記2

このような返答をいただいた。

つまり、metaとしては依然としてRelayへの依存を剥がすことが困難であり、RSCのドッグフーディングはできていないのであえてGraphQLをやめるモチベーションはないと。

とすると、Foundationから名前を消したのも単に手離れした(Apollo等アクティブなコミュニティに任せた)だけかもしれない。

また、

@defer/stream のついたフィールドの返却を遅延させることができる。これがうまくRSCと統合されれば、例えば子に@defer付きのfragmentをばらまいてそれぞれを別でサスペンドさせることも可能になるのかもしれない…。

これに関しては面白いスクラップがあった。技術的には可能そうだが課題もありそう。