Upgrade to Pro — share decks privately, control downloads, hide ads and more …

より速い WEB を目指す Next.js / nextjs-make-the-web-faster

Takepepe
November 24, 2021

より速い WEB を目指す Next.js / nextjs-make-the-web-faster

【Next.js Update!】v12リリースを踏まえ、Next.jsの採用を考える

本発表は以下URLでアーカイブ視聴が可能です。https://youtu.be/KaS3bgz_CA4

イベントページ:https://forkwell.connpass.com/event/228457/

Takepepe

November 24, 2021
Tweet

More Decks by Takepepe

Other Decks in Technology

Transcript

  1. Agenda ▪ 前半:Next.js Conf 2021 おさらい / ▪ 後半:Next.js 12

    発表をうけて ▪ Static x Dynamic ▪ React Server Components x Edge ▪ Next.js x Granular Renderings ▪ Next.js x Granular Prefetch ▪ Next.js x Granular Chunks
  2. Next.js Conf 2021 の発表 Next.js Conf 2021 における発表内容は、 Next.js・React 開発の転換期到来アナウンスとなりました。

    現時点では実験的な機能(beta / alpha版)が多いですが、 その発表内容は大きなインパクトがありました。
  3. Next.js Conf 2021 の参考資料 Next.js at the Edge - Suzanne

    Aldrich + Lee Robinson - (Next.js Conf 2021) https://www.youtube.com/watch?v=WlP2TB2ORL4 Blog - Next.js 12 https://nextjs.org/blog/next-12 前半36Pまでは、上の動画内容をおさらいします
  4. Next.js の歴史 Server-Side Rendering SSR Automatic Static Optimization Static Site

    Generation SSG Incremental Static Regeneration ISR Next.js は SSR framework としてスタート。
  5. Next.js の歴史 Server-Side Rendering SSR Automatic Static Optimization Static Site

    Generation SSG Incremental Static Regeneration ISR 続いて、Automatic Static Optimization を導入しました。
  6. Next.js の歴史 Server-Side Rendering SSR Automatic Static Optimization Static Site

    Generation SSG Incremental Static Regeneration ISR Static Site Generation を採用し、Hybrid Framework に。
  7. Next.js の歴史 Server-Side Rendering SSR Automatic Static Optimization Static Site

    Generation SSG Incremental Static Regeneration ISR ISR を採用し、リビルド不要でページ更新を可能に。
  8. Next.js の歴史 Server-Side Rendering SSR Automatic Static Optimization Static Site

    Generation SSG Incremental Static Regeneration ISR ページ単位で「きめ細かい (Granular) 」戦略を取れる仕組みを提供しました。
  9. Static vs Dynamic これまで Next.js が提供してきたソリューションで明るみになったのは ▪ Static(getStaticProps / getStaticPaths)

    ▪ Dynamic(getServerSideProps) この両者が、スピードとパーソナライズで対立していることでした。
  10. Static x Dynamic = Edge USER ORIGIN Edge (Computing) は

    CDN と同様に、ユーザーとオリジンの中間に位置します。 Edge
  11. Static x Dynamic = Edge USER ORIGIN この Edge で処理する仕組みとして

    middleware (beta) が導入されました。 Middleware
  12. No Cold Starts, 100x Faster middleware は Vercel Edge Functions

    という厳密なランタイムで実行されます ▪ V8 を使用した JavaScript & WASMエンジンで構築されている ▪ fetch 関数など、標準の Web API ※ に限られる ▪ Native Node.js API はサポート外(fs等) ▪ Native Node.js API に非依存の node_modules は利用可 ※ 標準の Web API:ESM、Fetch、Stream、AbortController、など。 Web上のサービスが提供する RESTやGraphQL APIのことではない 【詳細】Edge Runtime https://nextjs.org/docs/api-reference/edge-runtime
  13. No Cold Starts, 100x Faster この制限のある環境下において、 仮想マシン or コンテナで起動する Node.js

    よりも 100倍高速な起動を提供することが可能になっています。 100 x Faster
  14. No Cold Starts, 100x Faster middleware で可能な一例に、以下の機能が挙げられます ▪ Authentication ▪

    Bot Protection ▪ Redirects ▪ Browser Support ▪ Feature Flags ▪ A/B Testing ▪ Server-Side Analytics ▪ Logging
  15. No Cold Starts, 100x Faster 例えば geo location に応じ、 静的ページを出し分けることが

    可能になります。 【詳細】Next.js at the Edge https://youtu.be/WlP2TB2ORL4?t=368
  16. No Cold Starts, 100x Faster middleware はセルフホスティング環境であっても、 Next.js の標準的なビルドで利用可能に(Node.js の

    sandbox 内)※ Vercel にデプロイする場合、middleware は Edge に展開。 開発者はインフラ構成を気にすることなく、 デフォルトでこの機能が有効になります。 ※ セルフホスティング環境では「 No Cold Start, 100x Faster」にはなりません
  17. React Server Components x Edge Next.js Conf 2021 で最大の驚きは(少なくとも私は) React

    チームと協力し React 18 サポートの準備を開始したこと、 そして React Server Components(aplha版)が Next.js で利用可能になるという発表です。 ※ React Server Components サポートは、React 18 サポートより未来になる認識 ※ React Server Components サポート時期について言及: https://github.com/reactwg/react-18/discussions/37
  18. React Server Components x Edge 従来 SSR (getServerSideProps) での課題 ▪

    データ取得完了まで、レスポンスを返却できない ▪ サーバーからのレスポンスを待つ間、真っ白な画面が表示される ▪ 全ての HTML が表示されるか否か
  19. React Server Components x Edge React Server Components x Edge

    で得られるメリット ▪ Edge 関数から即座に Streaming が開始されるため、待つ事がない ▪ 段階的にレンダリングを行い、完了したものから Streaming ▪ ブラウザ向け JS が最小限に、インタラクティブになるまでが高速に ▪ サーバー側で計算するため、非力なデバイスでも高速に
  20. React Server Components x Edge で得られるメリット ▪ Edge 関数から即座に Streaming

    が開始されるため、待つ事がない ▪ 段階的にレンダリングを行い、完了したものから Streaming ▪ ブラウザ向け JS が最小限に、インタラクティブになるまでが高速に ▪ サーバー側で計算するため、非力なデバイスでも高速に TTFB/ LCP/ FID など、Web Vitals 向上に貢献 React Server Components x Edge
  21. getServerSideProps / getStaticProps は将来不要に ▪ データフェッチ関数をコンポーネントと同じ場所に配置可能になる ▪ 必要に応じて最小限のスクリプトが送られ、段階的に Hydrate される

    ▪ 将来的に ISR の様な、ページ単位のキャッシュは必要なくなる ▪ その代わりに「コンポーネントレベル」で詳細なキャッシュが可能になる React Server Components x Edge
  22. granular component caching という展望 ▪ Suspense 境界のように機能する「Data」コンポーネントを検討している ▪ コンポーネント単位で surrogate

    keys を発行し個別でパージ可能に ▪ コンポーネント単位で revalidate 秒数指定が可能に ▪ React Server Components と Edge functions のイノベーションで可能になった React Server Components x Edge
  23. ひとつは、誰もがすぐに開発を始められることです。 Dan Abramov 氏が Create React App 発足の動機として語る様に、 過去、フロントエンド開発環境の準備は敷居が高いものでした。 Next.js

    Conf 2021 感想 Before CRA, the ecosystem was hopelessly fragmented. The entire category of tools like this didn't exist — there was no Next or Gatsby or Vite and so on. The vast majority of React developers were setting up their Babel, webpack, etc, manually, and having a really bad time. These tools were difficult to get working together correctly. ” ※ 引用:https://github.com/facebook/create-react-app/issues/11180
  24. Next.js Conf 2021 感想 今日、Next.js / Gatsby / Vite を利用すれば、あまり意識せずとも、

    フロントエンド開発のベストプラクティス恩恵を、 開発初期から受けることができます。 ※ 引用:https://github.com/facebook/create-react-app/issues/11180 Before CRA, the ecosystem was hopelessly fragmented. The entire category of tools like this didn't exist — there was no Next or Gatsby or Vite and so on. The vast majority of React developers were setting up their Babel, webpack, etc, manually, and having a really bad time. These tools were difficult to get working together correctly. ”
  25. 最も着目すべきは、React や Next.js が 「Web Vitals」を指針に、 「ユーザー体験向上を中心に進化」している点です。 React Server Components

    x Edge も 例外なくこの取り組みの一環だと思います。 Next.js Conf 2021 感想 ※ 引用:https://web.dev/vitals/
  26. Next.js Conf 2021 のデモにあったとおり、 React Server Components は HTML と

    最小限の JavaScript しか届けません。 細切れな生成済み HTML を段階的に hydrate するため、 低スペック端末でも快適な UX の提供が期待できます。 Next.js Conf 2021 感想
  27. Next.js はこれまで、ページ単位で Rendering を選択するという 「きめ細かい (Granular)」アプローチを提供してきました。 これが Web Vitals にどの様に貢献するのか、

    Next.js Conf 2021 で発表された新しい Rendering とあわせ、    ※ TTFB (Time To First Byte) サーバーの初期応答時間 / FCP (First Contentful Paint) 視覚コンテンツの初期表示時間 ※ LCP (Largest Contentful Paint) 最大視覚コンテンツの表示時間 / FID (First Input Delay) 初回入力までの遅延時間 LCP FID TTFB FCP を比較していきましょう。 Next.js x Granular Renderings
  28. Origin Server API Server/DB 静的 HTML Cache がない場合、TTFB までは実質 SSR

    と同じ。 FID Request LCP FCP TTFB No Cache 【2】ISR (fallback: “blocking”) Edge CDN
  29. Origin Server API Server/DB 生成した HTML は Edge CDN に

    Cache される。 FID Request Cache LCP FCP TTFB No Cache 【2】ISR (fallback: “blocking”) Edge CDN
  30. ▪ ビルドタイムに静的生成せず、オンデマンドで静的生成が可能 ▪ Cache がある場合、Edge CDN から HTML が返るため高速 ▪

    Cache がない場合、SSR と同様に Rendering を blocking ▪ クローラーにコンテンツを確実にインデックスさせたい場合に利用 【2】ISR (fallback: “blocking”)
  31. Origin Server API Server/DB JSON と同時に静的 HTML が生成され、Edge CDN に

    Cache される。 FID LCP FCP Request TTFB Cache Cache 【3】ISR (fallback: true) Edge CDN
  32. ▪ ビルドタイムに静的生成せず、オンデマンドで静的生成が可能 ▪ Cache がある場合、Edge CDN から HTML が返るため高速 ▪

    Cache がない場合、Skeleton を返すため TTFB までが速い ▪ クローラーに Skeleton がインデックスされるリスクがあった 【3】ISR (fallback: true)
  33. ▪ ビルドタイムに静的生成せず、オンデマンドで静的生成が可能 ▪ Cache がある場合、Edge CDN から HTML が返るため高速 ▪

    Cache がない場合、Skeleton を返すため TTFB までが速い ▪ クローラーに Skeleton がインデックスされるリスクがあった Next.js 12 で追加された「Bot-Aware ISR Fallback」で心配なくなった。 【3】ISR (fallback: true) ※ Bot-Aware ISR Fallback の RFC:https://github.com/vercel/next.js/discussions/28180
  34. Origin Server API Server/DB 静的 HTML Cache が Edge CDN

    から高速に配信。 FCP Request TTFB 【4】Static (Cache) + CSR Edge CDN
  35. Origin Server API Server/DB Static Generation だけでなく、SSR でも用いられる構成。 FCP Request

    TTFB 【4】Static (Cache) + CSR LCP FID Edge CDN ※ LCP相当のコンテンツデータを fetch している前提
  36. Origin Server API Server/DB JS ファイルがロードされた後に hydrate、fetch が開始。LCP までが遅い。 LCP

    FCP Request TTFB 【4】Static (Cache) + CSR Slow FID Edge CDN ※ LCP相当のコンテンツデータを fetch している前提
  37. 【4】Static (Cache) + CSR ▪ Edge CDN の高速配信で TTFB を高速に

    ▪ JS ファイルのロード完了後に fetch が開始するため、LCP までが遅い ▪ 常に新しいデータを取得するため、データ整合性が担保できる ▪ 部分的にパーソナライズ可能であり、個人情報なども表示できる ※ LCP相当のコンテンツデータを fetch している前提
  38. ここから Next.js Conf 2021 で発表された 新しい Rendering 【5】Streaming with getServerSideProps

    (RFC) 【6】Streaming SSR @ Edge (alpha) 既存の getServerSideProps 拡張・React 17 でも使え【6】への移行を容易に
  39. ここから Next.js Conf 2021 で発表された 新しい Rendering 【5】Streaming with getServerSideProps

    (RFC) 【6】Streaming SSR @ Edge (alpha) React Server Components を使い、React 18 以降が必要
  40. Origin Server API Server/DB コンテンツデータ (LCP 相当) を取得する前に <head />

    を返却、TTFB が速い。 FCP Request TTFB 【5】Streaming with getServerSideProps <head /> Edge CDN
  41. Origin Server API Server/DB そのため、従来 SSR と比較し CSS / JS

    ロードが前倒しに。 FCP Request TTFB 【5】Streaming with getServerSideProps コンテンツデータ (LCP相当) CSS / JS Edge CDN
  42. Origin Server API Server/DB ここが Streaming で、このレスポンスは <head /> と同じもの。

    FID LCP FCP Request TTFB 【5】Streaming with getServerSideProps Streaming Edge CDN
  43. 【5】Streaming with getServerSideProps ▪ Next.js 12 にはまだ搭載されておらず、RFC段階 ▪ getServerSideProps が返す「props」に変更が加えられる

    ▪ 従来 SSR のボトルネックであった、TTFB 遅延が改善 ▪ データ取得開始のタイミングが CSR より前なので LCP までが速い ▪ 次の【6】Streaming SSR@Edge への準備として有用 【詳細】Streaming in Next.js - Kara Erickson - (Next.js Conf 2021) https://youtu.be/Nl4OwNhh2QI?list=TLGG9L6VQs5dRz4xNTExMjAyMQ
  44. API Server/DB Edge Computing でも Skeleton を返却する FCP Request TTFB

    Edge Computing 【6】Streaming SSR @ Edge (alpha)
  45. API Server/DB 断片的に送られてきた HTML を順次 Hydrate する FID LCP FCP

    Request TTFB 【6】Streaming SSR @ Edge (alpha) Edge Computing
  46. API Server/DB React Server Components の初期表示にはこの Streaming SSR が使われる。 FID

    LCP FCP Request TTFB 【6】Streaming SSR @ Edge (alpha) Streaming Edge Computing
  47. 【6】Streaming SSR @ Edge (alpha) ▪ まだ試験的な段階で、一部機能が試せるようになったばかり ▪ Edge からの

    Streaming 配信により、全ての高速化が期待される ▪ インフラを自由に選択できるのは、さらに将来の話になりそう 【詳細】Next.js at the Edge - Suzanne Aldrich + Lee Robinson - (Next.js Conf 2021) https://www.youtube.com/watch?v=WlP2TB2ORL4
  48. Next.js x Granular Renderings ▪ コンテンツの性質に応じた Rendering が選択できているか ▪ 静的事前生成エリア・データ取得エリアは、適切に分離できているか

    ▪ Skeleton のデザインは考慮されているか パフォーマンスのために、デザイン面でも積極的に議論を。
  49. Next.js x Granular Prefetch 提供されている Granular Renderings を選ぶだけでは、 3つの Core

    Web Vitals の指標のうち「CLS」の対策がとれません。 「視覚的な安定性」は、コンテンツの高さ変動に起因します。 これは Suspense の様な多段レンダリングはもちろん、 ...loading 表示(Skeleton 表示)についてまわる課題です。 ※ CLS(Cumulative Layout Shift)「累積レイアウト シフト数」視覚的な安定性を測定するための指標。
  50. Next.js x Granular Prefetch ここで活きるのが「SWR」等のライブラリです。 Suspense と似たコンポーネント構成を取ることができ、 CSR における非同期データ取得を簡単にしてくれます。 そして

    Navigation に伴う ...loading 表示を削減し、 視覚的に安定した Navigation を提供できます。 ※ 以降「 Navigation 」は SPA における遷移を指します
  51. CSR (Each Request) Edge / Origin API Server/DB あるページからの Navigation

    で、データを取得し CSR する例です。 Navigation Prev Page
  52. CSR (Each Request) Edge / Origin API Server/DB Component マウントを

    hook にした fetch の場合、 Navigation Prev Page
  53. SWR (No Cache) Edge / Origin API Server/DB In-Memory SWR

    を利用したデータ取得を見ていきます。Cache はまだ有りません。 Navigation Prev Page
  54. SWR (No Cache) Edge / Origin API Server/DB In-Memory SWR

    で Component マウントと同時にデータを取得した場合、 Navigation Prev Page
  55. SWR (No Cache) Edge / Origin API Server/DB In-Memory 取得したデータを

    Memory (ブラウザ) に Cache します。 Navigation Prev Page Cache
  56. SWR (With Cache) Edge / Origin API Server/DB In-Memory この

    Cache がある場合、データが即座に返るので ...loading は表示されません。 Navigation Prev Page
  57. SWR (With Cache) Edge / Origin API Server/DB In-Memory 取得したデータは新しい

    Cache として、次回活用されます。 Re-Render Navigation Prev Page Cache
  58. SWR (Programmatically Prefetch) Edge / Origin API Server/DB In-Memory そこで、Navigation

    前にデータを取得してしまうのが Prefetch です。 Navigation Prev Page Cache
  59. SWR (Programmatically Prefetch) Edge / Origin API Server/DB In-Memory mutate

    を先行して実行すると、あらかじめ取得したデータを Cache できます。 Navigation Prev Page Cache ※ Programmatically Prefetch:https://swr.vercel.app/docs/prefetching#programmatically-prefetch
  60. next/link (Prefetch) Navigation Prev Page Cache API Server/DB next/link による

    Prefetch は、SWR による Prefetch と同等の効果があります。 In-Memory Edge / Origin ※ Route prefetching in Next.js: https://web.dev/route-prefetching-in-nextjs/
  61. SWR (Programmatically Prefetch) Edge / Origin API Server/DB In-Memory SWR

    の Cache Prefetch は、パーソナライズドデータも扱えます。 Navigation Prev Page Cache
  62. Next.js x Granular Prefetch いずれの Prefetch も視覚的安定性に有用です。 しかし「表示されるであろう予測」にもとづくデータ取得は、 無駄になってしまう事もあります。 next/link

    は大味な Prefetch がデフォルトなので、注意が必要です。 【参考】Link と ISR が引き起こす Next.js の過負荷 https://zenn.dev/takepepe/articles/nextjs-isr-prefetch
  63. Next.js x Granular Prefetch SWR では Prefetch を行う Component は提供されていません。

    next/link と同じように振る舞う Component を用意すれば、 遷移後の ...loading 表示を限りなく抑えられるでしょう。 過度の Prefetch とならないよう、バランスを取ることが肝心です。
  64. Next.js x Granular Prefetch 【Next.js には不向きですが余談】 まさにこの Client Side の

    Cache Prefetch 機構を実現したのが 「React Location」です。 React Query 作者の Tanner 氏が router ライブラリとして先日発表。 routing と prefetching のインテグレーションを提供しています。 【参考】React Location https://react-location.tanstack.com/
  65. SPA Chunk Problems Next.js の様なフレームワークがなかったころ、 SPA は単一の chunk に結合されてしまうなど、 適切に

    chunk 分割されているとは限りませんでした。 chunk 分割はやや敷居が高く、 誰もが無意識にできていた事ではありませんでした。
  66. SPA Chunk Problems 2ページ追加したことで、Chunk が 50 KB 増加しました。 Single Chunk

    130 KB + 50 KB Page Bytes Page Sources Common Sources 130 KB 130 KB
  67. Chunk Per Page 従来 SPA においては、この課題が顕著でした。 Next.js では「ページ単位」で chunk が分割されるため、

    自然と必要最小限のコードのみが、 立ち上げ時にロードされる様になります。
  68. Chunk Per Page ページ単位の chunk 分割のほか、 Google Chrome チーム (現

    Aurora チーム) の協力のもと、 部分的に共通している実装を効率的に chunk 分割する 「granular chunking」が導入されたことも話題になりました。 【詳細】Improved Next.js and Gatsby page load performance with granular chunking https://web.dev/granular-chunking-nextjs/
  69. 本来は必要なページでのみ、20 KB 増加としたいです。 Page Chunk 80 KB Page Bytes Page

    Sources Common Sources 50 KB 80 KB + 20 KB 60 KB 50 KB + 20 KB Common Sources Problems
  70. しかし設計都合で _app に実装を追加するしかなく、共通 Sources が肥大化。 Page Chunk 100 KB +

    20 KB Page Bytes Page Sources Common Sources 70 KB + 20 KB 80 KB + 20 KB 80 KB + 20 KB 70 KB + 20 KB + 20 KB _app.tsx Common Sources Problems
  71. 全てのページで 20 KB の増加が余儀なくされました。 Page Chunk 100 KB + 20

    KB Page Bytes Page Sources Common Sources 70 KB + 20 KB 80 KB + 20 KB 80 KB + 20 KB 70 KB + 20 KB + 20 KB _app.tsx Common Sources Problems
  72. また、型安全のために自動生成した fetch client でも 不要な実装を含めてしまう懸念があります。 aspida は `outputEachDir: true` を指定しなければこの状態になりますし、

    graphql-codegen でも以下参考記事のように分割指定をするべきです。 OpenAPI から型定義のみ出力する、というのも良いでしょう。 Common Sources Problems 【参考】next.jsでのファイルチャンク最適化の一例 https://blog.hiroppy.me/entry/2021/08/12/092839
  73. 以下の観点で、設計初期から共通 Sources 肥大化に気をつけましょう。 ▪ chunk 分割しやすい状態管理ライブラリを使っているか ▪ 自動生成される fetch client

    等は、ユースケース単位で分割できているか ▪ Context Provider の適用範囲は、ページ単位に閉じることはできないか ▪ _app に実装を追加する場合、将来どの様に肥大化するか想定しておく Common Sources Problems
  74. Conclusion 近年 Aurora チームの密接な連携により、 Next.js を使用したサイトの 91% 以上が 優れた Core

    Web Vitals を獲得したそうです。 誰もが最適化の恩恵を受けている証です。 ※ 引用:https://twitter.com/hdjirdeh/status/1457679313965240325
  75. Conclusion 【詳細】Performance as a default with Next.js https://web.dev/performance-as-a-default-with-nextjs/ これまでの取り組みの内容は web.dev

    に寄稿があります。 Next.js に搭載された機能とあわせて、 パフォーマンスにどう向き合うべきか 調べてみましょう。 ※ 引用:https://twitter.com/hdjirdeh/status/1457679327630266369