Closed7

nextのSSR、ISRについて考える(本当にgetServerSidePropsはそこまで避けるべきものか?)

terrierscriptterrierscript
  • ISRはgetStaticPropsを利用していて、「Static Generate」とあるが、実態としてSSRと同じようにサーバー上で処理することで動いている
    • yarn startすることで動いている
    • このためvercel上や、CloudRunなどでは動き、serverlessな環境では動かせない
    • 個人的な感覚で言えば、この挙動はサーバー起動しているアプリケーションの前段にnginxでキャッシュを仕掛けているような構成と似たようなものではないかと感じている(Railsのページキャッシュのようなものと言っても近そう)
  • ただnext.jsのドキュメント上で言えばこれをStatic Generationと呼んでるっぽい気がする
    • ServerSideとStaticの違いはreq, resへアクセス出来ることと定義している節を感じる。
terrierscriptterrierscript
  • ISRがgetStaticPropsを利用しており、reqへアクセス出来ない事によって、ユーザーのログイン状態をしたレンダリングが出来ないようになっている。
    • これは確かに良いことで、通常のWebアプリケーションでよくある、愚直に全部キャッシュしてしまってログイン情報が漏れてしまったみたいな事故に繋がりづらそう。
    • 例えばURLに認証トークンを仕込むような形式だと事故は起きうる(例えば/order/[orderId]みたいなページで認証をすべきところでしてなかったケースなど?)
terrierscriptterrierscript

つまり本当は

  • server target
    • ISR
    • SSR
  • serverless target
    • export html

な気がするのだが見せ方的に

  • dynamic generate
    • SSR
  • static generate
    • ISR
    • export html

の区分をしているように見えるのが腹落ちしない原因っぽい

terrierscriptterrierscript

getServerSidePropsを使うとき・使わないとき

  • When should I use getStaticProps?
    にはThe data can be publicly cached (not user-specific).とある一方でWhen should I use getServerSideProps?にはYou should use getServerSideProps only if you need to pre-render a page whose data must be fetched at request time. とあって、露骨にgetStaticProps推し(getServerSideProps下げ)を感じる
  • ではuser-specifiedなデータを出したいときはどうするか?という点についてはFetching data on the client sideということでClientでfetchしろ、と誘導している

ほんとに?

  • 個人的には上記については微妙に疑義が残る
  • 例えばユースケースとして、ログインしている人に追加なコンポーネントを出すという場合であればこれはその通りclientでfetchするのが妥当というのは理解できる
  • 一方でそれ以外のユースケースとして、全てのページがログイン必須な場合や、UXとSEOの兼ね合いで、初回レンダリングの時点で分離させたいというケースでgetServerSideProps存在するであろうと推察する(後述)
terrierscriptterrierscript

全ページログイン必要な場合

  • この場合、クライアントフェッチでも確かに可能であるが、その場合全ページにおいてAPIとpagesを分離して書く必要が出てくる。
    • そうなると結局RESTにおけるgetな部分はgetServerSidePropsの機能として書いてしまうほうが楽ではいか?と体感では感じる
    • 管理画面的なノリであれば、paginationすらAPIを通さず/someItem/list/[pageNum]的にしてgetServerSidePropsに任せたほうが楽に感じる
  • getServerSidePropsで例えばRDBアクセスなどをした場合、connection poolingを適切に考えなければ適切に動かないという問題がありそうだ
    • 一方でこの問題はgetServerSidePropsで行おうが/api以下のNextApiHanderで行おうがつきまとう問題となる。
    • 特にその結果別なAPIをproxyするような場合であれば、結局getServerSidePropsでやったほうが怠惰に進められそうだ。

UXとSEOの兼ね合いで初回レンダリングを変えたい場合。

  • 例えば「会員登録して続きを読む」みたいな場合を想定する
  • この場合、ログイン済みの会員には初回レンダリングからすべて表示されている状態にして、非会員ならマスクさせるという風にしたい
  • この場合は結局素直にgetServerSidePropsを使ったほうが素直ではなかろうか?
  • getServerSidePropsを使わないで解決方法を考える
    • 解決方法1: URLを会員用/非会員用で分ける
      • なんとなく過去の経験からするとSEO担当者から嫌がられそうだ・・・
      • あと会員が目的のページに遷移するのに1クリック増える事になりそう
    • 解決方法2: 非会員の状態(マスクあり)でpre-renderingして、client side fetchをして会員の場合はマスクを置き換える
      • これで解決は出来るが、おそらくローディング後にガチャっとずれて(あの現象名前なんて言うんだっけ・・・)若干ストレスの貯まる画面になりそうだ
catnosecatnose

ガチャッとずれる現象はLayout Shiftですかね…?

ちなみにZennで記事や本を表示するときは、ISR + クライアント側でのSWR(的なもの)という感じにしています。ただ、getStaticPropsとクライアント側の2箇所でAPIリクエストをするのはややこしいので、本当にパフォーマンスを優先したいページだけISRを使うようにしています。

このスクラップは2020/12/27にクローズされました