Next.js チュートリアルを実践

https://nextjs.org/learn/

チュートリアルで作成したもの

前提知識

Next.js

  • Universal (Isomorphic) JavaScript フレームワーク

    • SPA で問題となるのがSEO対策、初回ロード時間
    • SSR はこれを解決してくれるが、クライアントとサーバでロジックの重複が発生
      • => 同じコードをクライアントとサーバで実行 (Isomophic)
      • => 同じコードをネイティブアプリやデスクトップアプリや組み込みデバイスでも実行 (Universal)
  • 特徴

SPA (Single Page Application)

  • 画面の描画や遷移をクライアントサイドの JavaScript ですべて行う Web アプリケーション

  • 特徴

    • ページ遷移が発生しない
      • 同一のページ内でコンテンツのみを切り替える
  • メリット

    • 高速
      • 従来のサーバがページごとに HTML をレンダリングするのに比べて、SPA は必要な部分だけ API でデータを取得し再描画を行う為、高速
    • フロントエンドとサーバサイドを完全に分離して開発出来る
  • デメリット

    • 初期表示に時間がかかる

SSR (Server-Side Rendering)

  • ブラウザで行われていたJSの実行とHTML生成をサーバー側(=Node.js)で行う技術

  • メリット

    • SPA の欠点である 初期表示の遅さ がカバーされる
  • デメリット

    • サーバ(=Node.js が動かせるサーバ)が必要

Pre-rendering

  • パフォーマンス(高速化)、SEO の向上の為に、予め各ページの HTML を生成しておく事

Pre-rendering vs SSR

  • Pre-rendering

    • 事前に生成したHTMLを配信
  • SSR

    • アクセスを受けて、HTMLを生成・配信

SSG (Static Site Generation)

  • 「事前に SSR を行って静的ファイル化しておき、本番環境では生成済みのHTMLを配信するだけ」 というアプローチ

    • Next.js では next export コマンドで Static HTML Export (=静的ファイル化)できる
  • メリット

    • サーバが不要
      • 生成済みの静的ファイルを S3 等でホストすればok

SSR vs SSG

チュートリアル実施時のメモ

Create a Next.js App

npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn-starter/tree/master/learn-starter"
  • 開発サーバの起動
cd nextjs-blog
yarn dev

Navigate Between Pages

  • Next.js における「ページ」とは

  • Next.js の Routing

    • ページは ファイル名 に基づいてルーティングに関連づけられる
  • クライアントサイドでのアプリ内の異なるページへの遷移

  • コード分割(Code splitting) と プリフェッチング(prefetching)

    • Next.js は自動的にコード分割を行う
    • 各ページはそのページに必要なものだけを読み込む
    • Link コンポーネント
      • ブラウザの viewport に表示されると、自動的にリンク先のページをバックグラウンドでプリフェッチする

Assets, Metadata, and CSS

  • CSS スタイリング
    • CSS-in-JS library により行われる

Pre-rendering and Data Fetching

Pre-rendering

  • Pre-rendering

    • why
      • パフォーマンス、SEO の向上
    • how
      • 予め各ページの HTML を生成しておく
        • 生成された各 HTML は JavaScript コードと関連づけられる
        • ブラウザがページをロードした際に、上記の JavaScript コードが実行される
  • Next.jsPre-rendering

    • 2 つの方式がある
      1. Static Generation
      2. Server-side Rendering
    • ページ毎にどちらの方式を使用するか選択できる
  • Static Generation (静的生成)

    • ビルド時 に HTML を生成する Pre-rendering 手法
    • 対処ページをユーザーのリクエストに先立って生成できる場合は、Static Generation を推奨
  • Server-side Rendering (サーバサイドレンダリング, SSR)

    • 毎回のリクエスト毎 に HTML を生成する Pre-rendering 手法
  • (備考) Pre-rendering されているかの確認方法

Data Fetching

  • getStaticProps

    • Static Generation 用のAPI
    • 外部データを使用する際は、getStaticProps() 内で取得
    • ビルド時に、サーバサイド で実行される
      • ビルド時のみ実行されるよう想定されている為、リクエスト時にしか利用できないデータ(=クエリパラメータ、HTTPヘッダ 等)を使用する事は出来ない
    • pages/ 以下の .js, .jsx, .ts, .tsx ファイルでのみ getStaticProps() を export 可能
  • getServerSideProps

    • Server-side Rendering 用のAPI
    • リクエスト時に、サーバサイドで実行される
  • (備考) getInitialProps

    • ページがレンダリングされる前に実行されるAPI
    • 状況によって実行環境(サーバサイド or クライアントサイド)が変化するため下記のような問題があった
      • SSG した際に、next link を使用して getInitialProps を使用しているページに、クライアントサイドでルーティングを行った際に、再度クライアント側で getInitialProps が実行されてしまう
    • 今後は getInitialProps の代わりに getStaticProps, getServerSideProps 等の利用を推奨
  • クライアントサイドレンダリング

    • Pre-rendering する必要がない場合に用いる下記の手法
      1. 外部データを必要としないページの部分を Static GeneratePre-rendering
      2. ページをロードした際に、クライアント側で、JavaScript を使用して外部データを取得
        • SWR を使用して外部データを取得する事を推奨
  • SWR (stale-while-revalidate)

Dynamic Routing

  • Dynamic Routing

    • 外部データに応じて、ページのパスを動的に生成し、ページを静的に生成する事
    • ページのパスを動的に生成 - => getStaticPaths

    • ページを静的に生成 - => getStaticProps

  • Dynamic Routing での静的ページ生成

    • http://localhost:3000/posts/<id> というページを静的生成する場合
      • /pages/posts/[id].js ファイルを作成し、下記のような React コンポーネントを作成する
        • getStaticPaths() を実装し、id として取りうる値のリストを返す
        • getStaticProps() を実装し、id に基づいて必要なデータを取得する
// /pages/posts/[id].js

export default function Post() {
    // React コンポーネントを返す
}

export async function getStaticPaths() {
    // id としてとりうる値のリストを返す
    return [
        {
            params: {
                id: ['a', 'b', 'c'] //ここを、外部データに応じて動的に返すようにする
            }
        }
    ]
}

export async function getStaticProps({ params }) {
  // params.id を使用して、ページに必要なデータを取得する
  // この例では、params.id は ['a', 'b', 'c'] のようになる
}
  • 開発環境 vs 本番環境
    • 開発環境
      • getStaticPaths は毎回のリクエストごとに実行される
    • 本番環境
      • getStaticPaths はビルド時に実行される

API Routes

  • API Route

    • Next.js アプリの中に API エンドポイントを作成できる
  • API エンドポイントの作成

    • http://localhost:3000/api/hello というAPI エンドポイントを作成する場合は、pages/api/hello.js を作成する
// pages/api/hello.js

export default (req, res) => {
  res.status(200).json({ text: 'Hello' })
}
  • Dynamic API Routes を作成する事もできる

  • 留意点

    • getStaticPropsgetStaticPaths 内で API Route を fetch しない事
      • getStaticPaths はビルド時にサーバサイドで実行される(=クライアントからは実行されない)ので、クライアント向けの API を fetch せず、サーバサイド向けの処理を直接書く事

Deploying Your Next.js App

TypeScript

  1. tsconfig.json の作成 + TypeScript のインスール
yarn add --dev typescript @types/react @types/node
touch tsconfig.json
yarn dev
  1. 既存のファイルの拡張子を js から ts / tsx に変更し、適宜、型を設定する