Slide 1

Slide 1 text

Next.js 研修 2023 2023年4月20日 リクルート64期新人BC_エンジニアコース

Slide 2

Slide 2 text

講師の自己紹介 吉井 健文 @Takepepe / フロントエンド関連の記事書いたり 所属:横断エンジニアリング部 ASG 2020年10月入社、Next.js を採用したプロジェクトの 開発支援を中心に、横断従事

Slide 3

Slide 3 text

Time Table ■【第1章】フロントエンド開発と SPA フレームワーク(15m) ■【第2章】Next.js の SPA(30m) ■【第3章】Next.js の BFF(60m)  → 昼休憩(12:00 〜 13:00) ■【第4章】 Next.js と パフォーマンス(90m) ■【第5章】Next.js と ライブラリ(60m)  → 休憩(15:30 〜 16:00) ■【第6章】簡単なアプリを作ってみよう( 120m) ✏ 研修用 GitHub リポジトリのクローンをお願いします https://github.com/recruit-tech/bootcamp-2023-nextjs

Slide 4

Slide 4 text

Time Table ■【第1章】フロントエンド開発と SPA フレームワーク(15m) ■【第2章】Next.js の SPA(30m)📌:2-x ■【第3章】Next.js の BFF(60m)📌:3-x  → 昼休憩(12:00 〜 13:00) ■【第4章】 Next.js と パフォーマンス(90m)📌:4-x ■【第5章】Next.js と ライブラリ(60m)📌:5-x  → 休憩(15:30 〜 16:00) ■【第6章】簡単なアプリを作ってみよう( 120m)📌:5-x スライドの解説中(📌:2-x)の様にサンプルコードの箇所を参照することがあります https://github.com/recruit-tech/bootcamp-2023-nextjs

Slide 5

Slide 5 text

Time Table ■【第1章】フロントエンド開発と SPA フレームワーク(15m) ■【第2章】Next.js の SPA(30m)📌:2-x ■【第3章】Next.js の BFF(60m)📌:3-x  → 昼休憩(12:00 〜 13:00) ■【第4章】 Next.js と パフォーマンス(90m)📌:4-x ■【第5章】Next.js と ライブラリ(60m)📌:5-x  → 休憩(15:30 〜 16:00) ■【第6章】簡単なアプリを作ってみよう( 120m)📌:5-x 解説中、迷子になった場合( 📌)で検索して該当コードを見つけてください https://github.com/recruit-tech/bootcamp-2023-nextjs

Slide 6

Slide 6 text

開発環境の確認 ■ 最新の Node.js(18.16.0 LTS) ■ Docker Desktop ■ リポジトリをクローンしたら、 node_moduels をインストールしておきましょう  → $ npm i 上記の開発環境が整っていることを前提に、研修を進めます

Slide 7

Slide 7 text

React と Next.js の関係を解説します。 Next.js のような SPA フレームワークが必要になる背景をおさえます。 第1章 フロントエンド開発と      SPA フレームワーク

Slide 8

Slide 8 text

第1章 フロントエンド開発と SPA フレームワーク JSX(TSX)は、 UI コンポーネント(View)を関数で実装します ■ 入力(Props)を与えると、出力(HTML)を得る ■ 要素一覧、ボタン、フォームなど ■ 小さい UI コンポーネントを組み上げる  → ページ相当の UI コンポーネントが出来る  → 先日の React 研修のとおり UI コンポーネント単位の開発

Slide 9

Slide 9 text

第1章 フロントエンド開発と SPA フレームワーク React は UI ライブラリ ■ UI コンポーネント実装・レンダリングに特化 ■ ページとして提供する方法は、別途必要になる  → Web アプリケーションサーバーとしての機能は持たない UI コンポーネント単位の開発

Slide 10

Slide 10 text

第1章 フロントエンド開発と SPA フレームワーク MPA はリクエストごとに HTML を表示 ■ MPA は SPA との対比で使用される用語  → Multi Page Application / Single Page Application ■ 複数 の HTML ページで構成される  → サーバーが HTML をレスポンス  → 状態の復元は Cookie などを頼りに SPA・MPA の違い 画面遷移毎に「ページのリクエスト」が発生するもの HTML 画面遷移 HTML HTML 画面遷移

Slide 11

Slide 11 text

第1章 フロントエンド開発と SPA フレームワーク SPA は DOM を適宜書き換えることで、画面遷移 ■ 初回レスポンスは、単一 HTML ■ URL 変更(History API)に応じて JSON を非同期で取得 ■ JSON を HTML コンテンツとして書き換え  → 仮想 DOM を更新・実 DOM に反映  → ブラウザ上で動的に HTML に反映 SPA・MPA の違い 画面遷移毎に「コンテンツの書き換え」が発生するもの HTML 画面遷移 画面遷移 JSON JSON

Slide 12

Slide 12 text

第1章 フロントエンド開発と SPA フレームワーク ✅ SPA/MPA の違いは「画面遷移」である ■ SPA は画面遷移しても、ブラウザの状態が破棄されない  → 一度取得したデータ、ユーザーの状態を維持できる ■ 非同期で必要なコンテンツのみをダウンロードする  → データソースアクセスが必要最小限に  → 画面遷移が高速 SPA・MPA の違い HTML 画面遷移 画面遷移 JSON JSON React は SPA のためとは限らない

Slide 13

Slide 13 text

第1章 フロントエンド開発と SPA フレームワーク 単一の HTML で SPA 展開するもの ■ 典型的な SPA(古典的な SPA) ■ 初期描画では不要な JavaScript バンドルのロードが発生  → FID ※1 の低下に直結 ■ 最適化にはチューニングが必要 フレームワークを採用する利点 HTML 画面遷移 画面遷移 JSON JSON 初回ロードで大量の JavaScript バンドルファイルを取得する必要 大量のJavaScript 課題 ※1 FID(First Input Delay)コアウェブバイタルの指標の 1つ。初回入力までの遅延時間。

Slide 14

Slide 14 text

第1章 フロントエンド開発と SPA フレームワーク React 公式がフレームワーク使用を推奨 ※1 している ■ 新しいアプリを作る場合になぜ推奨されるのか?  → アプリの肥大化に応じて FID が遅くなりがち(バンドルサイズの肥大化)  → データ取得のニーズが多様化(データ取得の然るべきタイミングと頻度)  → React に限らず、他フロントエンド実装でも同様のチューニングが必要 フレームワークを採用する利点 主にパフォーマンス観点で、フレームワークが欠かせなくなっている ※1 Can I use React without a framework? :https://react.dev/learn/start-a-new-react-project#can-i-use-react-without-a-framework

Slide 15

Slide 15 text

第1章 フロントエンド開発と SPA フレームワーク 複数の HTML で SPA 展開するもの ■ Next.js、Remix、Sveltekit、Nuxt、...etc ■ バンドラーを含み、ページ毎のレスポンス(ダウンロードファイル)が最適化 ■ ページによって、動的・静的にレスポンスを選択する フレームワークを採用する利点 HTML 画面遷移 画面遷移 JSON JSON 具体的にどのようなアプローチが採用されるのか、1日の研修を通して解説します SPA フレームワーク 解決 ?

Slide 16

Slide 16 text

第1章 フロントエンド開発と SPA フレームワーク ✅ React 単体よりも、良いアプリケーション開発が可能 ■ バンドラー、ルーター、データ取得の最適解が盛り込まれている ■ 配信方法の最適解は、多様化している ■ Next.js は SPA 以外にも、ニーズにあわせて選択可能 ■ コンテンツの性質に応じて選べる フレームワークを採用する利点

Slide 17

Slide 17 text

Next.js は SPA 構築を容易にし、快適な開発体験を提供します。 まったく新しいプロジェクト作成から、ハンズオンをスタートしましょう。 第2章 Next.js の SPA

Slide 18

Slide 18 text

第2章 Next.js の SPA create next app を実行してみよう ■ create next app とは?  → Next.js プロジェクトの雛形生成ツール ■ $ npx create-next-app@latest 【実技】Next.js プロジェクトを作ってみよう (消す前提なので)まずは適当なディレクトリで試してみましょう

Slide 19

Slide 19 text

第2章 Next.js の SPA # プロジェクト名称は? ✔ What is your project named? … my-app # TypeScript 使う? ✔ Would you like to use TypeScript with this project? … No / Yes # ESLint(コーディング規約)使う? ✔ Would you like to use ESLint with this project? … No / Yes # Tailwind CSS(CSS フレームワーク)使う? ✔ Would you like to use Tailwind CSS with this project? … No / Yes # 「src」ディレクトリ使う? ✔ Would you like to use `src/` directory with this project? … No / Yes # 「app」ディレクトリ使う? ✔ Would you like to use experimental `app/` directory with this project? … No / Yes # import エイリアスは? ? What import alias would you like configured? › @/* 【実技】Next.js プロジェクトを作ってみよう

Slide 20

Slide 20 text

第2章 Next.js の SPA Next.js 開発サーバーを起動してみよう ■ $ cd my-app ■ $ npm run dev ■ http://localhost:3000/ を確認してみよう ■ 「Ctrl + C」で開発サーバーを終了 【実技】Next.js プロジェクトを作ってみよう ✅ Next.js プロジェクトの準備はこれで完了!

Slide 21

Slide 21 text

第2章 Next.js の SPA 研修リポジトリの「packages/chapter-2」を使用します ■ カレントディレクトリを移動して  → $ cd packages/chapter-2 ■ 開発サーバーを起動して  → $ npm run dev 【実技】pages ルーティングを体験してみよう 研修リポジトリのサンプルは、 create next app で作成しました

Slide 22

Slide 22 text

第2章 Next.js の SPA ファイルシステムベースのルーティング ■ フォルダ構成と命名規則で、ルーティングが決まる packages/chapter-2/src/pages ├── about.tsx ├── blog │ └── [slug].tsx └── index.tsx 【実技】pages ルーティングを体験してみよう ← http://localhost:3000/about ← http://localhost:3000/blog/{slug} ← http://localhost:3000

Slide 23

Slide 23 text

第2章 Next.js の SPA ファイルシステムベースのルーティング ■ 「pages」 というディレクトリに「 Page ファイル」を配備する  → pages ディレクトリに配備するだけで、ルーティング対象となる  → ページ相当の UI コンポーネントを export default(📌:2-1) 【実技】pages ルーティングを体験してみよう

Slide 24

Slide 24 text

第2章 Next.js の SPA Link コンポーネントを使用した SPA ナビゲーション ■ import Link from "next/link";  → a要素のように使用。href 属性を指定する(📌:2-2) 【実技】pages ルーティングを体験してみよう

Slide 25

Slide 25 text

第2章 Next.js の SPA Router を使用した SPA ナビゲーション・参照 ■ import { useRouter } from "next/router";  → router.push を使用すると、SPA ナビゲーションできる( 📌:2-3)  → router.query を参照すると、path パラメーターが参照できる( 📌:2-4)  → router.query を参照すると、query パラメーターが参照できる( 📌:2-5) 【実技】pages ルーティングを体験してみよう

Slide 26

Slide 26 text

第2章 Next.js の SPA ファイルシステムの命名規則と、 Router の使い方が基本 ■ Link コンポーネントや Router を使用すると、SPA ナビゲーションができる ■ ページルーティングは、ファイルを配置するだけ ■ 命名規則によってリクエストパラメーターを取得できる ✅ 単純な SPA サイトなら、すぐに実装できる

Slide 27

Slide 27 text

第2章 Next.js の SPA 開発サーバー・本番サーバーは別物 ■ Next.js アプリ 開発サーバーの起動  → ■ Next.js アプリ(本番サーバー)のビルド  → ■ Next.js アプリ(本番サーバー)の起動  → 【実技】npm script を試してみよう

Slide 28

Slide 28 text

第2章 Next.js の SPA 開発サーバー・本番サーバーは別物 ■ Next.js アプリ 開発サーバーの起動  → $ npm run dev ■ Next.js アプリ(本番サーバー)のビルド  → $ npm run build ■ Next.js アプリ(本番サーバー)の起動  → $ npm start 【実技】npm script を試してみよう 研修後半、使い分けるため注意

Slide 29

Slide 29 text

第2章 Next.js の SPA TypeScript の型互換エラーがある状況でビルドしてみよう ■ const value: string = 0; を適当に追加 ■ $ npm run build  → 【実技】npm script を試してみよう

Slide 30

Slide 30 text

第2章 Next.js の SPA TypeScript の型互換エラーがある状況でビルドしてみよう ■ const value: string = 0; を適当に追加 ■ $ npm run build  → Type error: Type 'number' is not assignable to type 'string'. 【実技】npm script を試してみよう 型互換エラーがあるとビルドに失敗する

Slide 31

Slide 31 text

ESLint コーディング規約違反がある状況でビルドしてみよう ■ (📌:2-6)の行を削除 ■ $ npm run build  →  ■ $ npm run lint eslint の実行(コーディング規約違反チェック)  →  第2章 Next.js の SPA 【実技】npm script を試してみよう

Slide 32

Slide 32 text

ESLint コーディング規約違反がある状況でビルドしてみよう ■ (📌:2-6)の行を削除 ■ $ npm run build  → Type error: Property 'alt' is missing in type ■ $ npm run lint eslint の実行(コーディング規約違反チェック)  → Warning: Image elements must have an alt prop 第2章 Next.js の SPA 【実技】npm script を試してみよう ESLint コーディング規約違反があるとビルドに失敗する

Slide 33

Slide 33 text

Next.js は Web アプリケーションサーバーとして機能します。 SSR(Server Side Rendering)や Web API の実装を施す「BFF」機能を見ていきましょう。 第3章 Next.js の BFF

Slide 34

Slide 34 text

第3章 Next.js の BFF Web アプリケーションサーバーとしての機能 ■ SSR(Server Side Rendering)機能  → データ取得  → リクエスト単位の検証(認証認可)  → 正常系以外のレスポンス(リダイレクト、エラー表示) Next.js の BFF とは SSR は SEO 観点でも必要になることがある

Slide 35

Slide 35 text

第3章 Next.js の BFF Web アプリケーションサーバーとしての機能 ■ Web API 機能  → データ取得・更新  → リクエスト単位の検証(認証認可)  → クレデンシャル情報を扱う外部連携 Next.js の BFF とは 静的サイトとの大きな違い

Slide 36

Slide 36 text

第3章 Next.js の BFF 外部サーバー(サブシステム)との中継役を担い、永続層と接続する ■ VPC ネットワーク内の外部サーバー(サブシステム)と疎通  → バックエンド API サーバーと疎通  → API サーバーから取得したデータの集約(アグリゲーション) ■ DB サーバーと疎通  → Prisma など ORM 経由で Next.js の BFF とは システム構成によって使い分けることができる

Slide 37

Slide 37 text

第3章 Next.js の BFF 基本 Node.js サーバーとして稼働 ■ ランタイムは Node.js 以外も選べる(次世代の話)  → Edge Runtime  → 今日の研修では触れません Next.js の BFF とは システム構成によって使い分けることができる

Slide 38

Slide 38 text

第3章 Next.js の BFF ✅ Next.js は Web アプリケーションサーバーとして利用できる ■ 単一 Next.js プロジェクトコードで、フロント・ BFF 実装ができる ■ 完全に静的なサイトジェネレーターとしても利用できる Next.js の BFF とは

Slide 39

Slide 39 text

第3章 Next.js の BFF 研修リポジトリの第3章をひらき、開発サーバーを起動しましょう ■ カレントディレクトリを移動して  → $ cd packages/chapter-3 ■ 開発サーバーを起動して  → $ npm run dev 【実技】SSR を試してみよう

Slide 40

Slide 40 text

第3章 Next.js の BFF getServerSideProps(gSSP)とは? ■ ページに向けたデータ取得関数  → ページリクエストのたび、実行される  → サーバーログを確認してみよう( 📌:3-1) ■ SSR(Server Side Rendering)向け  → 取得したデータを埋め込み、 HTML をレスポンス 【実技】SSR を試してみよう

Slide 41

Slide 41 text

第3章 Next.js の BFF 動的パラメーターの取得 ■ gSSP の引数 ctx.query から query・path パラメーターが参照できる( 📌:3-2) ■ gSSP が定義されている場合、 useRouter の挙動が変わる(📌:3-3) 【実技】SSR を試してみよう getServerSideProps あり getServerSideProps なし

Slide 42

Slide 42 text

Cookie の参照 ■ gSSP では Cookie の読み書きができる( 📌:3-4)  → nookies(Next.js で Cookie を扱いやすくするライブラリ) ■ Cookie にセットした sessionID から、session 値を参照  → session 値を使用した外部リクエストなど 第3章 Next.js の BFF 【実技】SSR を試してみよう

Slide 43

Slide 43 text

第3章 Next.js の BFF ✅ gSSP はページのレンダリングだけでなく、リクエスト検証が行える ■ ログインユーザーに紐づいた情報の取得 ■ VPC 内のバックエンド API サーバー(サブシステム)との連携に ■ サーバーで実行されるため、クレデンシャル情報を扱える 【実技】SSR を試してみよう

Slide 44

Slide 44 text

第3章 Next.js の BFF Next.js では環境変数を参照する仕組みが提供されている ■ .env ファイル(📌:3-5)  → MY_SECRET_VAR(サーバーでのみ参照できる)   → NEXT_PUBLIC_VAR(クライアント・サーバーで参照できる) 【実技】環境変数を参照してみよう 「NEXT_PUBLIC_」接頭辞がついた環境変数は、クライアントにも公開される

Slide 45

Slide 45 text

第3章 Next.js の BFF SSR では環境変数が参照できる( 📌:3-6) ■ gSSP で取得した環境変数は、 props を経由すると…  → フロントでも参照できてしまう  → やってはダメ 󰢃 【実技】環境変数を参照してみよう

Slide 46

Slide 46 text

第3章 Next.js の BFF コンポーネントから直参照するとどうなる?( 📌:3-7) ■ NEXT_PUBLIC_ 接頭辞を持つ環境変数は、 client JavaScript のバンドルに含まれる ■ NEXT_PUBLIC_ 接頭辞を持たない環境変数の直参照は、 Hydration エラーが発生 ■ Hydration とは?  → 1. Server で生成した DOM を HTML 文字列化(SSR/SSG)  → 2. Client で HTML 文字列を DOM に復元する処理(イベントハンドラのアタッチ)  → 1・2の DOM に差があると、エラーが起こる( Hydration エラー) 【実技】環境変数を参照してみよう

Slide 47

Slide 47 text

第3章 Next.js の BFF .env には種類がある ■ .env.production というファイルを用意すると、 production モードでのみ適用  → $ npm run build && npm start  → http://localhost:3000/check_env_in_component ■ .env*.local という名前でファイル作成すると、優先適用  → $ echo NEXT_PUBLIC_VAR=override_public_local > .env.local  → $ npm run dev  → .gitignore にあらかじめ設定されている  → .env は git 管理されてしまうので、クレデンシャル情報は含めないこと 【実技】環境変数を参照してみよう

Slide 48

Slide 48 text

第3章 Next.js の BFF ✅ 環境変数定義の方法が豊富 ■ .env ファイルを使用することで、環境変数が定義できる ■ サーバーランタイムだけでなく、ブラウザランタイムでも参照できる  → 「NEXT_PUBLIC_」接頭辞をつける  → 露出して問題ない定数か注意する ■ ビルドモードによって設定を細かく指定できる ■ 環境変数はビルドタイムで決まる  → ランタイムで決める方法もある  → https://nextjs.org/docs/api-reference/next.config.js/runtime-configuration 【実技】環境変数を参照してみよう

Slide 49

Slide 49 text

第3章 Next.js の BFF API Routes とは? ■ Next.js が提供する Web API の構築方法 ■ getServerSideProps と同様にサーバーサイドの処理ができる ■ SPA で必要になる Web API が実装できる 【実技】Web API を試してみよう

Slide 50

Slide 50 text

第3章 Next.js の BFF Cookie を使用した counter 実装(📌:3-8) ■ http://localhost:3000/api/counter/memory ■ リクエストを送るごとにインクリメント ■ カウントは共有される 【実技】Web API を試してみよう トップレベル変数はサーバーメモリに(実際はこんな実装はほぼしない)

Slide 51

Slide 51 text

第3章 Next.js の BFF Cookie を使用した counter 実装(📌:3-9) ■ http://localhost:3000/api/counter/cookie ■ リクエストを送るごとにインクリメント ■ カウントは共有されない 【実技】Web API を試してみよう getServerSideProps と同様に Cookie を扱える

Slide 52

Slide 52 text

第3章 Next.js の BFF ✅ API Routes はリクエスト検証付きの Web API 実装ができる ■ 基本、ブラウザに表示された UI コンポーネントから利用される Web API  → 値をフォームに入力・ボタンを押下  → 値を送信する先が、 API Routes(Web API) ■ ログインユーザーに紐づいた情報の取得 ■ VPC 内のバックエンド API サーバー(サブシステム)との連携に ■ サーバーで実行されるため、クレデンシャル情報を扱える 【実技】Web API を試してみよう

Slide 53

Slide 53 text

第3章 Next.js の BFF Next.js が Fullstack フレームワークと呼ばれる所以 ■ SSR(getServerSideProps) ■ Web API(API Routes) ■ middleware 機能もある ✅ SPA と BFF を同時に構築できる Next.js は SPA フレームワークであり、 Web アプリケーションサーバーとして利用できる

Slide 54

Slide 54 text

Next.js は Web アプリケーション配信のパフォーマンスに貢献します。 ページ単位で選べる事前レンダリングと、パフォーマンスの関係を明らかにします。 第4章 Next.js と パフォーマンス

Slide 55

Slide 55 text

チャンクファイルとは? ■ 一塊の JavaScript バンドルファイル ■ ビルド時に確認できる  → 共有ファイル 第4章 Next.js と パフォーマンス チャンクファイルの分割

Slide 56

Slide 56 text

チャンクファイルとは? ■ 一塊の JavaScript バンドルファイル ■ ビルド時に確認できる  → ページ毎のファイル 第4章 Next.js と パフォーマンス チャンクファイルの分割

Slide 57

Slide 57 text

チャンクファイルとは? ■ 一塊の JavaScript バンドルファイル ■ ビルド時に確認できる  → ページ毎の First Load 第4章 Next.js と パフォーマンス チャンクファイルの分割 First Load JS 量がグリーンのページはバンドルサイズが十分小さく、良好なページ

Slide 58

Slide 58 text

チャンクファイルが分割されないとどうなるのか? ■ どのエントリーポイント(ページのリクエスト)でも、全ページ分の取得 Web サーバー 第4章 Next.js と パフォーマンス チャンクファイルの分割 画面遷移 画面遷移 HTML 単一の HTML ファイル・JavaScript バンドルをレスポンス(古典的な SPA ) 大量のJavaScript 課題 JSON JSON /page-a のリクエスト /page-b のリクエスト /page-c のリクエスト

Slide 59

Slide 59 text

チャンクファイルが分割されないとどうなるのか? ■ どのエントリーポイント(ページのリクエスト)でも、全ページ分の取得 Web サーバー 第4章 Next.js と パフォーマンス チャンクファイルの分割 画面遷移 画面遷移 HTML つまり、ページが増えるほどアプリの起動が遅くなる 大量のJavaScript 課題 JSON JSON /page-a のリクエスト /page-b のリクエスト /page-c のリクエスト

Slide 60

Slide 60 text

Web サーバー 第4章 Next.js と パフォーマンス ページ単位で、必要最低限のチャンクファイルが分割出力されるように ■ 新規機能・新規ページを追加しても、既存ページの初期動作は遅くならない チャンクファイルの分割 必要最低限のJavaScript /page-b 分割 /page-b のリクエスト

Slide 61

Slide 61 text

Web サーバー 第4章 Next.js と パフォーマンス ページ単位で、必要最低限のチャンクファイルが分割出力されるように ■ 新規機能・新規ページを追加しても、既存ページの初期動作は遅くならない チャンクファイルの分割 必要最低限のJavaScript 必要最低限のJavaScript 必要最低限のJavaScript /page-a /page-b /page-c 分割 分割 分割 /page-a のリクエスト /page-b のリクエスト /page-c のリクエスト

Slide 62

Slide 62 text

第4章 Next.js と パフォーマンス Next.js に限らず、SPA メタフレームワークは Web サーバーも含む ■ リクエストに応じて、対応するページを返却 チャンクファイルの分割 必要最低限のJavaScript 必要最低限のJavaScript 必要最低限のJavaScript /page-a /page-b /page-c /page-a のリクエスト /page-b のリクエスト /page-c のリクエスト Web サーバー(Next.js) 分割 分割 分割

Slide 63

Slide 63 text

第4章 Next.js と パフォーマンス 静的ファイルだけで構成される時(静的サイトの場合)も分割される ■ 動的ルートページを含む場合、 Web サーバー(Nginx 等)でルーティングが必要            → 分割されるため、静的サイトでも Next.js 採用にメリット チャンクファイルの分割 必要最低限のJavaScript 必要最低限のJavaScript 必要最低限のJavaScript /page-a /page-b /page-c /page-a のリクエスト /page-b のリクエスト /page-c のリクエスト Web サーバー(Nginx 等) 分割 分割 分割

Slide 64

Slide 64 text

第4章 Next.js と パフォーマンス ✅ ブラウザに送信する JavaScript バンドルサイズはパフォーマンスに直結する ■ Next.js に限った話ではない。 JavaScript バンドルサイズ削減が求められる ■ フレームワーク・ライブラリは JavaScript バンドルサイズを減らす工夫を続けている  → granular chunking  → https://web.dev/granular-chunking-nextjs/ ■ 最新の React 18 で追加された Server Components は、バンドルサイズの削減に繋がる チャンクファイルの分割 React・Next.js は、パフォーマンス向上を目的として進化

Slide 65

Slide 65 text

第4章 Next.js と パフォーマンス 事前レンダリングとは? ■ リクエスト発生前に、ページをレンダリングしておくこと ■ 事前レンダリングを適切に選択すると、  → オリジンサーバー( Next.js)の処理(負荷)を軽減できる  → リソースサーバー( Backend API サーバー)へのアクセスも減る ■ システム全体を俯瞰して、パフォーマンス面でのメリットが生まれる 事前レンダリング SSG(SG)と呼ばれるページレンダリング手法

Slide 66

Slide 66 text

第4章 Next.js と パフォーマンス SSG/SSR すると SPA にはならない? ■ ページに直アクセスした場合、 HTML を得る ■ SPA ナビゲーションでページにアクセスした場合、 JSON を得る ■ 画面回遊においては、ページのリソースとなる JSON を都度取得する 事前レンダリング /page-a /page-b /page-c A B C /page-c /page-a /page-b C A B

Slide 67

Slide 67 text

第4章 Next.js と パフォーマンス SSG/SSR すると SPA にはならない? → NO ■ 直接アクセス・SPA ナビゲーションに備え「両方」用意される  → 事前レンダリングは、 HTML・JSON を静的ファイルとして両方出力する ■ SSR ページはリクエストに応じて、 HTML・JSON を都度出し分ける  → getServerSideProps は、HTML を SSR するだけの関数ではない! 事前レンダリング /page-a A /page-b B /page-c C

Slide 68

Slide 68 text

第4章 Next.js と パフォーマンス リクエスト前にあらかじめ出力するので、パブリックなページ向け ■ パーソナルなページには使えない  → パーソナルなページの CDN キャッシュ → キャッシュ事故 󰢃 ■ 画面構成に応じて選ぶ  → ページの大部分がパーソナル  → SSR  → ページの小部分がパーソナル  → SSG + CSR 事前レンダリング

Slide 69

Slide 69 text

第4章 Next.js と パフォーマンス リクエスト前にあらかじめ出力するので、パブリックなページ向け ■ パーソナルなページには使えない  → パーソナルなページの CDN キャッシュ → キャッシュ事故 󰢃 ■ 画面構成に応じて選ぶ  → ページの大部分がパーソナル  → SSR  → ページの小部分がパーソナル  → SSG + CSR 事前レンダリング SSR は遅い? → NO / 画面構成によっては SSR の方が速い(LCP※1 , FID 観点) ※1 LCP(Largest Contentful Paint)コアウェブバイタルの指標の 1つ。ユーザーの認識としてのページ表示速度を測る指標。

Slide 70

Slide 70 text

第4章 Next.js と パフォーマンス .next というディレクトリに、静的ファイルが出力される ■ Vercel の場合  → .next ディレクトリが CDN に同期され、静的ファイルとして配信 ■ Self-Hosting の場合  → .next ディレクトリを共有マウントで管理する必要がある 事前レンダリング .next ディレクトリを眺めながら、事前レンダリングの挙動を確認していきます

Slide 71

Slide 71 text

第4章 Next.js と パフォーマンス あらかじめ Backend API サーバーを起動しておきます ■ カレントディレクトリを移動して  → $ cd packages/backend-api ■ Backend API サーバーを起動しておく  → $ npm run dev  → http://localhost:8080/api/now 【実技】事前レンダリングを試してみよう モックのニュースデータを返す Express API サーバー

Slide 72

Slide 72 text

第4章 Next.js と パフォーマンス 研修リポジトリの「packages/chapter-4」を使用します ■ カレントディレクトリを移動して  → $ cd packages/chapter-4 【実技】事前レンダリングを試してみよう

Slide 73

Slide 73 text

第4章 Next.js と パフォーマンス production モードで起動して、3 種類のレンダリングの違いを確認してみよう ■ $ npm run build でビルドする ■ packages/chapter-4/.next に出力される静的ファイルを確認しよう  → .next/server/pages/news/isr に静的ファイルが出力されていない  → .next/server/pages/news/ssg に静的ファイルが出力されている  → .next/server/pages/news/ssr に静的ファイルが出力されていない ■ $ npm start で起動する ■ $ npm run restart で再ビルド・起動する 【実技】事前レンダリングを試してみよう 事前レンダリングの挙動をデバッグするためには、本番サーバーを起動する必要があります

Slide 74

Slide 74 text

第4章 Next.js と パフォーマンス .next というディレクトリの事前レンダリングファイル ■ Vercel の場合  → .next ディレクトリが CDN に同期され、静的ファイルとして配信 ■ Self-Hosting の場合  → .next ディレクトリを共有ボリュームで管理する必要がある 【実技】事前レンダリングを試してみよう

Slide 75

Slide 75 text

第4章 Next.js と パフォーマンス SSR ページの挙動(📌:4-1、📌:4-2) ■ http://localhost:3000/news/ssr にアクセスしてみよう ■ Backend API サーバーには、都度リクエストが発生する 【実技】事前レンダリングを試してみよう Backend API サーバーのアクセス時刻( accessedAt)は都度更新される

Slide 76

Slide 76 text

第4章 Next.js と パフォーマンス SSG ページの挙動(📌:4-3、📌:4-4) ■ http://localhost:3000/news/ssg にアクセスしてみよう ■ Backend API サーバーには、一切リクエストが発生しない Backend API サーバーのアクセス時刻( accessedAt)は一切更新されない 【実技】事前レンダリングを試してみよう

Slide 77

Slide 77 text

第4章 Next.js と パフォーマンス ISR(Incremental Static Regeneration)ページの挙動(📌:4-5、📌:4-6) ■ http://localhost:3000/news/isr にアクセスしてみよう ■ Backend API サーバーには、稀にリクエストが発生する ■ 再発生する間隔は 4 秒 【実技】事前レンダリングを試してみよう Backend API サーバーのアクセス時刻( accessedAt)は稀に更新される

Slide 78

Slide 78 text

第4章 Next.js と パフォーマンス Backend API を遅くし(📌:4-7)TTFB(Time to first byte)を比較してみよう 【実技】事前レンダリングを試してみよう 意図的に、Backend API のレスポンスに 1000ms の待機時間を挿入 27ms Backend API 遅延なしSSR

Slide 79

Slide 79 text

第4章 Next.js と パフォーマンス SSR は Backend API が遅いほど、体験に直結 【実技】事前レンダリングを試してみよう Backend API 遅延あり SSR の場合 27ms 1020ms Backend API 遅延なしSSR Backend API 遅延ありSSR

Slide 80

Slide 80 text

SSG は Backend API が遅くても、体験に直結しない! 第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Backend API 遅延あり SSG の場合 27ms 6ms Backend API 遅延なしSSR Backend API 遅延ありSSG

Slide 81

Slide 81 text

…ただしビルド時間が伸びる ■ 事前レンダリングページ数 x Backend API 速度 = ビルド時間 第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう 数万・数十万ページの事前レンダリングは、現実的ではない Backend API 遅延なしビルド Backend API 遅延ありビルド

Slide 82

Slide 82 text

ビルド時に事前レンダリングするページは、指定できる( 📌:4-8) ■ getStaticPaths 関数の paths 配列の文字列数  → .next/server/pages/news/ssg に出力される静的ファイル数 第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう paths 配列が 0件の場合、ビルド時間は変わらない Backend API 遅延なしビルド Backend API 遅延ありビルド

Slide 83

Slide 83 text

ビルド時に事前レンダリングされないページは、アクセスするとどうなる? ■ http://localhost:3000/news/ssg にアクセスして、リンクを踏んでみよう  → .next/server/pages/news/ssg/{slug} 静的ファイルが出力されるのはいつ? ■ http://localhost:3000/news/ssg/{slug} に直アクセスしてみよう  → .next/server/pages/news/ssg/{slug} 静的ファイルが出力されるのはいつ? 第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう アクセスする前に静的ファイルが出力されている??

Slide 84

Slide 84 text

ビルド時に事前レンダリングされないページは、アクセスするとどうなる? ■ http://localhost:3000/news/ssg にアクセスして、リンクを踏んでみよう  → .next/server/pages/news/ssg/{slug} 静的ファイルが出力されるのはいつ? ■ http://localhost:3000/news/ssg/{slug} に直アクセスしてみよう  → .next/server/pages/news/ssg/{slug} 静的ファイルが出力されるのはいつ? 第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう アクセスする前に静的ファイルが出力されている?? 注目

Slide 85

Slide 85 text

第4章 Next.js と パフォーマンス Link コンポーネントからの被リンクで、投機的な事前レンダリング ■ prefetch: false の場合リンク先ページは「事前レンダリングされない」( 📌:4-9)  → ただし、マウスオーバーで「事前レンダリングされる」 ■ prefetch: true の場合リンク先ページが「事前レンダリングされる」( 📌:4-10)  → ただし、Link コンポーネントが画面に表示されそうなとき  → Intersection Observer API が内部で使用されている  → https://github.com/vercel/next.js/blob/canary/packages/next/src/client/link.tsx#L509-L560 【実技】事前レンダリングを試してみよう prefetch 未指定の場合はどっち?( 📌:4-11)

Slide 86

Slide 86 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a /page-a への直アクセス

Slide 87

Slide 87 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a page-a.html は未生成 page-a.html

Slide 88

Slide 88 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a データを取得して… page-a.html Fetch Data

Slide 89

Slide 89 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a 事前レンダリング page-a.html page-a.json page-a.html New Fetch Data

Slide 90

Slide 90 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a .next に出力(CDN に同期) page-a.html page-a.json page-a.html New Fetch Data

Slide 91

Slide 91 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a 出力された HTML をレスポンス page-a.html page-a.html page-a.json Response: /page-a page-a.html TTFB Fetch Data

Slide 92

Slide 92 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a /page-b へ遷移(するかもしれない) page-a.html page-a.html page-a.json Response: /page-a page-a.html TTFB Fetch Data

Slide 93

Slide 93 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a 事前生成された page-b.json がある場合 page-a.html page-a.html page-a.json Response: /page-a page-a.html page-b.json TTFB Fetch Data

Slide 94

Slide 94 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a 遷移前だが page-b.json をプリフェッチ(即レスポンス) page-a.html page-a.html page-a.json Response: /page-a page-a.html TTFB TTFB Fetch Data page-b.json

Slide 95

Slide 95 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a Link 押下で、プリフェッチした JSON でページ書き換え page-a.html page-a.html page-a.json Response: /page-a page-a.html Navigate: /page-b TTFB TTFB Fast Fetch Data page-b.json

Slide 96

Slide 96 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a Revalidate 期間が経過していた場合 page-a.html page-a.html page-a.json Response: /page-a page-a.html Navigate: /page-b TTFB TTFB Old Revalidate Fetch Data Old page-b.json

Slide 97

Slide 97 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a ユーザーの裏側でデータ取得 page-a.html page-a.html page-a.json Response: /page-a page-a.html Navigate: /page-b TTFB TTFB Revalidate Fetch Data Old page-b.json Fetch Data Old

Slide 98

Slide 98 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a ユーザーの裏側で再生成 page-a.html page-a.html page-a.json Response: /page-a page-a.html Navigate: /page-b TTFB TTFB page-b.html page-b.json Revalidate Fetch Data Old page-b.json Fetch Data Old New

Slide 99

Slide 99 text

第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Request: /page-a 次の誰かのアクセスのために事前レンダリング page-a.html page-a.html page-a.json Response: /page-a page-a.html Navigate: /page-b TTFB TTFB page-b.html page-b.json Revalidate Fetch Data page-b.json Old Fetch Data New

Slide 100

Slide 100 text

第4章 Next.js と パフォーマンス 投機的な事前レンダリングがされる条件( ISR の場合) ■ 事前レンダリング対象ページの、静的出力が「ない」こと ■ 事前レンダリング対象ページの、静的出力が「ある」場合  → 投機的な事前レンダリングは発動しない  → ページ遷移先の「出力済み」の JSON を返す  → Revalidate 期間が経過していた場合、裏側で「再出力」を試行   → 次回アクセス時は、最新のページに更新されている   → Stale-White-Revalidate ※1 の挙動 【実技】事前レンダリングを試してみよう ユーザーには 出力済みの JSON を即レスポンスし、裏側で重たい再出力が試行されている ※1 Stale-While-Revalidate ヘッダによるブラウザキャッシュの非同期更新: https://blog.jxck.io/entries/2016-04-16/stale-while-revalidate.html

Slide 101

Slide 101 text

第4章 Next.js と パフォーマンス ✅ Link コンポーネントは、ナビゲーション目的だけじゃない ■ 事前レンダリング対象ページは、被 Link によって投機的に生成される ■ 投機的な事前レンダリングは  → ハイパフォーマンスな配信になり得る 👍  → 過剰な API 呼び出しになり得る 👎 ■ SSR は投機的な事前レンダリング対象にならない 【実技】事前レンダリングを試してみよう 事前レンダリングのトリガーになる特別なコンポーネント

Slide 102

Slide 102 text

✅ 「オンデマンド」に静的ファイルが出力される ■ 事前レンダリングの「事前」とは?  → 󰢃 ビルド時 / 󰢐 ページリクエストが発生しそうな時(誰かの行動起因) ■ 事前レンダリングは、 HTML と JSON が同時出力される ■ getStaticPaths 関数の fallback は、オンデマンド生成のオプション  → 生成完了前に、サーバーがレスポンスするかの設定値 ■ getStaticProps 関数の revalidate は、オンデマンド再生成の間隔  → 秒数指定することで、 SSG は ISR になる 第4章 Next.js と パフォーマンス 【実技】事前レンダリングを試してみよう Next.js は SSR や Web API 機能を備え、オンデマンド SSG/ISR 機能を提供する

Slide 103

Slide 103 text

第4章 Next.js と パフォーマンス 【Appendix】Next.js v12.2 で追加された新機能 ■ On-Demand Revalidation  → 既に生成したページを、要求されたタイミングで再生成する  → API Routes に実装する(📌:4-12) ■ データソースが更新されたタイミングで呼び出す  → 例えば、CMS が更新された直後に再生成、など 【実技】事前レンダリングを試してみよう ISRの「一定時間経過後に再生成」というざっくりとした指定よりも緻密になった

Slide 104

Slide 104 text

Next.js の主要機能は「SPA・BFF・事前レンダリング」ですが、 十分なアプリケーション構築のためには、サードパーティライブラリが必要です。 第5章 Next.js と ライブラリ

Slide 105

Slide 105 text

第5章 Next.js と ライブラリ アプリケーション実装は、 Next.js だけでは賄えない複雑さがある ■ データ取得前のリクエスト検証  → バリデーションライブラリが欲しい( Zod) ■ フォーム実装が複雑になりがち  → フォーム実装ライブラリが欲しい( React Hook Form) Next.js と一緒によく使用されるライブラリ 最近よく採用するこの 2つのライブラリを紹介します

Slide 106

Slide 106 text

第5章 Next.js と ライブラリ 研修リポジトリの「packages/chapter-5」を使用します ■ カレントディレクトリを移動して  → $ cd packages/chapter-5 ■ 開発サーバーを起動して  → $ npm run dev 【実技】Zod を使ってみよう

Slide 107

Slide 107 text

第5章 Next.js と ライブラリ バリデーションスキーマを使用して、入力値を検証( 📌:5-1) ■ 入力値が 5 文字以内であることを期待 ■ schema.parse で検証を実施 【実技】Zod を使ってみよう

Slide 108

Slide 108 text

第5章 Next.js と ライブラリ オブジェクトをパースして検証( 📌:5-2) ■ 互換性がない場合、エラー ■ 互換性がある場合、型推論に反映される  → value: z.string() を value: z.number() に変更してみよう  → data.value の型推論はどうなる? 【実技】Zod を使ってみよう

Slide 109

Slide 109 text

第5章 Next.js と ライブラリ ✅ 静的解析(TypeScript)とランタイム検証が同時に行える ■ 不確かな値を扱う時、どこでも活用できる ■ バリデーション済みのオブジェクトは、型推論に反映される ■ Zod 使用を前提としたエコシステムが人気  → tRPC、Zodios,、resolver(React Hook Form) ■ 最近 Next.js 本体 devDependencies にも追加された  → https://beta.nextjs.org/docs/configuring/typescript#statically-typed-links  → https://github.com/vercel/next.js/pull/46962 【実技】Zod を使ってみよう

Slide 110

Slide 110 text

第5章 Next.js と ライブラリ React Hook Form の概要 ■ フォームを扱う処理は複雑になりがちである  → フォームを簡単に実装できる  → 高パフォーマンス(再レンダリング観点)で実装できる  → 非制御コンポーネントを使用したフォーム 【実技】React Hook Form を使ってみよう

Slide 111

Slide 111 text

第5章 Next.js と ライブラリ 通常盤:制御コンポーネントを使用したもの ■ フォームの入力値とエラーメッセージを管理する状態を用意する( 📌:5-3) ■ 制御コンポーネントを設置し、状態(入力値)を更新する ■ 入力値更新のたびに、再描画が走る ■ 送信を試みると、バリデーションとログイン処理を試行する( 📌:5-4) ■ バリデーション・エラーメッセージ更新・ログイン処理を順番に実施  → ✅ 送信前のバリデーションやエラー掲出を実装するには、それなりの処理が必要 【実技】React Hook Form を使ってみよう

Slide 112

Slide 112 text

第5章 Next.js と ライブラリ React Hook Form 版:非制御コンポーネントを使用したもの ■ 非制御コンポーネントとは ■ React で値を管理せず、DOM が保持する値を参照する ■ (📌:5-5)入力フォームのバリデーションを行うスキーマを用意する ■ (📌:5-6)Zod のスキーマを指定する ■ (📌:5-7)register、formState を使用した非制御コンポーネント(入力要素)を設置  → register 関数を展開すると、非制御コンポーネントに必要な props が展開される ■ (📌:5-8)バリデーションに成功したらログイン処理を実行する ■ (📌:5-9)API Routes 側でもバリデーションを行う 【実技】React Hook Form を使ってみよう

Slide 113

Slide 113 text

Next.js を使って、簡単なアプリを作ってみましょう。 BFF で ORM ライブラリ(Prisma)を使用して、DB にデータを保存してみましょう。 第6章 簡単なアプリを作ろう

Slide 114

Slide 114 text

第6章 簡単なアプリを作ろう ORM ライブラリの Prisma を使ってみよう ■ Prisma ざっくり概要  → Prisma Schema Language(PSL)でスキーマを書く  → スキーマから、各言語向けの Client が生成できる  → スキーマから、マイグレーションファイルが生成できる  → TypeScript との親和性が高い 今日の研修では Prisma 詳説はしません。予め用意したスキーマで開発を進めます。 【実技】簡単なアプリを作ってみよう https://www.prisma.io/docs

Slide 115

Slide 115 text

第6章 簡単なアプリを作ろう 研修リポジトリの「packages/chapter-6」を使用します ■ カレントディレクトリを移動して  → $ cd packages/chapter-6 ■ $ docker compose up -d  → posgres サーバー が立ち上がっていることを確認 【実技】簡単なアプリを作ってみよう

Slide 116

Slide 116 text

第6章 簡単なアプリを作ろう ORM ライブラリの Prisma を使ってみよう ■ Prisma をセットアップしよう ■ $ npm run db:migrate  → マイグレーション、 seeding を実行 ■ リセットは $ npm run db:migrate:reset で 【実技】簡単なアプリを作ってみよう

Slide 117

Slide 117 text

第6章 簡単なアプリを作ろう ORM ライブラリの Prisma を使ってみよう ■ Prisma Studio を使ってみよう  → Prisma に標準バンドルされている GUI  → $ npm run db:studio で Prisma Studio たちあげ  → $ http://localhost:5555 にアクセス 【実技】簡単なアプリを作ってみよう ✅ fixture が DB に挿入されていることを確認

Slide 118

Slide 118 text

第6章 簡単なアプリを作ろう ORM ライブラリの Prisma を使ってみよう ■ Prisma Studio でレコードを追加してみよう  → Add record ボタンを押下  → 新規内容を入力して  → Save 1 change ボタンを押下 【実技】簡単なアプリを作ってみよう ✅ Prisma Studio で、DB を操作できます

Slide 119

Slide 119 text

第5章 Next.js と ライブラリ DBのセットアップが完了したら、開発サーバーを起動します ■ カレントディレクトリを移動して  → $ cd packages/chapter-6 ■ 開発サーバーを起動して  → $ npm run dev 【実技】簡単なアプリを作ってみよう

Slide 120

Slide 120 text

第6章 簡単なアプリを作ろう 一連の CRUD 処理を確認しよう ■ (📌:6-1)Postテーブルから全件取得 ■ (📌:6-2)Postテーブルから ID が一致するレコードを取得 ■ (📌:6-3)サーバーで取得したデータを、初期値として設定 ■ (📌:6-4)ID が一致するレコードを更新 【実技】簡単なアプリを作ってみよう

Slide 121

Slide 121 text

第6章 簡単なアプリを作ろう 【課題】次の機能を追加で実装してみてください ✏ ① 記事を書く時「128文字以内の本文」を送信できるようにしてみよう ✏ ② 本文を編集できるようにしてみよう ✏ ③ 記事にタグを付けられるようにしてみよう ✏ ④ タグで記事一覧をフィルターできる機能を追加してみよう ✏ ⑤ 新規タグを作成できる機能を追加してみよう ✏ ⑥ タグテーブルのクエリーを減らすにはどうすれば良いか検討してみよう ⏰ 制限時間まで、自由に作り込んでみてください※ 【実技】簡単なアプリを作ってみよう