Slide 1

Slide 1 text

GraphQLを Server Componentsで使いたい BARフロントえんどう #1 2023.10.31 Ohnishi Taro(@taroro_tarotaro)

Slide 2

Slide 2 text

自己紹介 ● 大西太郎( @taroro_tarotaro) ● ベースマキナで管理画面のローコードSaaSを作ってます ● もうすぐエンジニア4年目に突入します🚀 ● GraphQL歴は半年弱くらい ● Next.js, Apollo Client, Go, gqlgen, Tailwind CSS, etc.

Slide 3

Slide 3 text

はじめに

Slide 4

Slide 4 text

はじめに 今後のリアーキテクチャでRSC(React Server Components)の考慮は必須… ● RSCを使うならできるだけSC(Server Components)に寄せたい ● SCの強みを活かしながらGraphQLを使えるか…?

Slide 5

Slide 5 text

GraphQLとは

Slide 6

Slide 6 text

GraphQLとは ● グラフ構造に従ってclientでフィールドを指定してデータ取得ができる

Slide 7

Slide 7 text

GraphQLとは ● グラフ構造に従ってclientでフィールドを指定してデータ取得ができる

Slide 8

Slide 8 text

GraphQLとは ● グラフ構造に従ってclientでフィールドを指定してデータ取得ができる ● 1リクエストでまとめて取得する ○ WaterFall問題への解決策の1つ ■ fetch→render→fetch→render … ● ※パフォーマンス以外にも良さはたくさんあるが省略… https://www.developerway.com/posts/how-to-fetch-data-in-react

Slide 9

Slide 9 text

GraphQLのよくある使い方 ● 1クエリ/ページが理想 ● 各コンポーネントで必要な値(Fragment)を宣言してルートで一括取得する ● 取った値はpropsかcontextで渡す

Slide 10

Slide 10 text

SCでGraphQLを使う

Slide 11

Slide 11 text

SCでGraphQLを使う SC(Server Components) ● Async Componentでのシンプルなデータ取得 ● DBに近い分、各Componentで取得してもWaterfallが気にならない ● Suspenseでのローディングとストリーミング

Slide 12

Slide 12 text

SCでGraphQLを使う SC(Server Components) × GraphQL ● Async Componentでのシンプルなデータ取得 ○ 取得はできる(Apolloなどの対応も進められている) ● DBに近い分、各Componentで取得してもWaterfallが気にならない ○ 1クエリ/ページなのでWaterfallにならないのは同様 ● Suspenseでのローディングとストリーミング

Slide 13

Slide 13 text

SCでGraphQLを使う SC(Server Components) × GraphQL ● Async Componentでのシンプルなデータ取得 ○ 取得はできる(Apolloなどの対応も進められている) ● DBに近い分、各Componentで取得してもWaterfallが気にならない ○ 1クエリ/ページなのでWaterfallにならないのは同様 ● Suspenseでのローディングとストリーミング ○ 1クエリ/ページなので全体がローディングされてしまう ○ 1クエリだからストリーミングは無理…?

Slide 14

Slide 14 text

SCでGraphQLを使う SC(Server Components) × GraphQL ● Async Componentでのシンプルなデータ取得 ○ 取得はできる(Apolloなどの対応も進められている) ● DBに近い分、各Componentで取得してもWaterfallが気にならない ○ 1クエリ/ページなのでWaterfallにならないのは同様 ● Suspenseでのローディングとストリーミング ○ 1クエリ/ページなので全体がローディングされてしまう ○ 1クエリだからストリーミングは無理…? ○ defer directive

Slide 15

Slide 15 text

defer directive GraphQL responseの一部を、clientで指定して遅延(defer)できる

Slide 16

Slide 16 text

defer directive GraphQL responseの一部を、clientで指定して遅延(defer)できる →@defer × SCで組み合わせられるか試す

Slide 17

Slide 17 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる

Slide 18

Slide 18 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる →@deferで分割したチャンクのpromiseをSCに渡す

Slide 19

Slide 19 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる →@deferで分割したチャンクのpromiseをSCに渡す 1. queryが呼ばれる 2. 各チャンクのpromiseを作る 3. promiseを各コンポーネントに渡す 4. 各チャンクが返ってきたらpromiseをresolveする

Slide 20

Slide 20 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる →@deferで分割したチャンクのpromiseをSCに渡す 1. queryが呼ばれる 2. 各チャンクのpromiseを作る 3. promiseを各コンポーネントに渡す 4. 各チャンクが返ってきたらpromiseをresolveする

Slide 21

Slide 21 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる →@deferで分割したチャンクのpromiseをSCに渡す 1. queryが呼ばれる 2. 各チャンクのpromiseを作る 3. promiseを各コンポーネントに渡す 4. 各チャンクが返ってきたらpromiseをresolveする

Slide 22

Slide 22 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる →@deferで分割したチャンクのpromiseをSCに渡す 1. queryが呼ばれる 2. 各チャンクのpromiseを作る 3. promiseを各コンポーネントに渡す 4. 各チャンクが返ってきたらpromiseをresolveする

Slide 23

Slide 23 text

GraphQL @defer × SC SCはpromiseを渡せばSuspenseでローディングできる →@deferで分割したチャンクのpromiseをSCに渡す 1. queryが呼ばれる 2. 各チャンクのpromiseを作る 3. promiseを各コンポーネントに渡す 4. 各チャンクが返ってきたらpromiseをresolveする

Slide 24

Slide 24 text

GraphQL @defer × SC promiseをどうやって渡すか…?

Slide 25

Slide 25 text

GraphQL @defer × SC promiseをどうやって渡すか…? props(Promise型のprops…?), context(SCにはない), ...

Slide 26

Slide 26 text

GraphQL @defer × SC promiseをどうやって渡すか…? props(Promise型のprops…?), context(SCにはない), ... →クラスのインスタンスでpromiseをキャッシュする

Slide 27

Slide 27 text

GraphQL @defer × SC promiseをどうやって渡すか…? props(Promise型のprops…?), context(SCにはない), ... →クラスのインスタンスでpromiseをキャッシュする ● React.cacheでリクエスト単位にできる https://zenn.dev/cybozu_frontend/articles/react-cache-and-nextjs

Slide 28

Slide 28 text

GraphQL @defer × SC promiseをどうやって渡すか…? props(Promise型のprops…?), context(SCにはない), ... →クラスのインスタンスでpromiseをキャッシュする ● React.cacheでリクエスト単位にできる https://github.com/apollographql/apollo-client-nextjs/blob/main/package/src/rsc/registerApolloClient.tsx#L6-L11

Slide 29

Slide 29 text

出来上がったもの(アプリケーションコードのみ) deferするかどうかは親が決めて子は知らなくて良いのも嬉しい

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

まとめ

Slide 32

Slide 32 text

まとめ ● 素朴にSCでGraphQLを使うとSuspenseでのストリーミングが活かせない ● defer directiveとpromiseのキャッシュでまるでComponent単位のfetchに…!

Slide 33

Slide 33 text

まとめ ● 素朴にSCでGraphQLを使うとSuspenseでのストリーミングが活かせない ● defer directiveとpromiseのキャッシュでまるでComponent単位のfetchに…! すぐ使えるか…? ● 今回試した方法は、あくまで僕が雑に作ったサンプル ● @deferなしならApollo Clientで取得可能 ● SC, @defer, Suspenseに対応したGraphQLクライアントはまだない…? ● @deferに対応したGraphQLサーバーも少ない…

Slide 34

Slide 34 text

まとめ ● 素朴にSCでGraphQLを使うとSuspenseでのストリーミングが活かせない ● defer directiveとpromiseのキャッシュでまるでComponent単位のfetchに…! まだ難しいところはいろいろ…(ぜひ懇親会でお話ししたいです󰢧) ● revalidate ● CCでのデータ取得 ● SSRからのhydration

Slide 35

Slide 35 text

ありがとうございました!