BLOG ブログ


2024.06.10 TECH

【Next.js】App Routerの特徴とPages Routerとの違いについて

Next.js 13.4から「App Router」というルーティング機能が安定版(Stable)となりました。

Next.js 13.4

ルーティングとは、Webサイト内で特定のURLにアクセスした際に表示するページを決定する仕組みのことです。
例: /aboutにアクセスしたら、Aboutページを返す など

この記事では「App Router」の特徴や、以前までのルーティング機能「Pages Router」との違いについて解説したいと思います。

※2024/05時点のNext.js最新バージョンは14.2です。

 

はじめに

Next.jsはReactのフレームワークとして、様々な機能が実装されています。

その中の1つに「ルーティング」があり、ファイルシステム(ディレクトリ構成)に沿ったページを生成してくれます。

pages
├── about
│   └── index.js  // https://example.com/about
├── help
│   ├── help01.js  // https://example.com/help/help01
│   └── help02.js  // https://example.com/help/help02
├── blog
│   └── [slug].js  // https://example.com/blog/[slug] (動的に可変)
└── contact
    └── index.js  // https://example.com/contact

これはとても便利な機能で、ディレクトリ内にファイルを配置するとディレクトリ名がURLパスとなり直感的にサイトを構築できるのが特徴です。

これはNext.jsに限ったことではなく他のフレームワーク(GatsbyやVueベースであるNuxtなど)でも採用されています。

しかし冒頭で述べた通りNext.js 13.4からは「App Router」という機能が実装され今までの「Pages Router」から進化しています。

 

なぜApp Routerが実装されたのか

まずはApp Routerが実装された理由を見てみます。

we received feedback from the community and identified areas
where we started to reach the limits of the Pages Router.
[翻訳]
コミュニティからのフィードバックを受け、Pages Routerの限界に達し始めた部分を特定しました。

Most notably, the Next.js Pages Router was not designed for streaming,
a cornerstone primitive in modern React
[翻訳]
最も注目すべき点は、Pages Routerが、
現代のReactの基本的な構造であるストリーミング用に設計されていないことです

Server Components, Suspense, and more,
which have been designed for streaming architectures.
[翻訳]
Server ComponentsやSuspenseなど、ストリーミングアーキテクチャ用に設計されたものです。

出典:Next.js App Router Update (2023/06/22)

これだけだと理解することは難しいのですが、Pages Routerではページの一部ではなく全体を返却するシステムだったため、Reactの基本構造とは離れた設計になっていたとのことです。

そのため後述する箇所の変更・アップグレードがなされたということみたいです。

 

共通点

変更点を挙げる前に、まず共通の仕様を説明します。

App RouterとPages Routerの両方ともファイルベースのルーティングを採用しています。

例に挙げた通り、ディレクトリ構成でルーティングが生成されることはどちらも変わりません。

またApp RouterとPages Routerは同時に使用できるため、Next.jsをアップグレードする際は、1つずつ順番にルーティングの対応を行うことが可能です。

// 下記のような構成でも併用可能です

// App Router
app
└── about     // https://example.com/about
   ├── layout.js
   └── page.js

// Pages Router
pages
├── help
│   ├── help01.js  // https://example.com/help/help01
│   └── help02.js  // https://example.com/help/help02
├── blog
│   └── [slug].js  // https://example.com/blog/[slug] (URLの一部が動的に変化)
└── contact
     └── index.js  // https://example.com/contact

App Router側にあるファイルのlayout.jsやpage.jsについては後述します。

 

変更点

では本題の変更点を説明します。

App Routerでは下記の項目が変わりました。

  • ディレクトリ配下のファイル名の変更(後述)
  • API Routes配下のファイル名
  • サーバーコンポーネント(後述)
    • サーバーコンポーネントとクライアントコンポーネント (Rendering)
  • ストリーミング
  • fetch (fetch)
    • Web APIのfetch()を拡張
      • キャッシュ制御(revalidate)機能が組み込まれている
  • getStaticProps, getServerSideProps, getStaticPathsの廃止
  • メタデータ (Metadata)
    • metadataオブジェクトかgenerateMetadata関数をlayout.jsかpage.jsに記述
    • faviconやOGPなどについてはappディレクトリに配置

全てではないですが、大きく変更となっている点を列挙しました。

個人的に大きく変わったと感じた点を下記で詳しく確認していきたいと思います。

 

ディレクトリ配下のファイル名の変更

Pages Routerではファイル名までURLパスとして認識されていましたが、 App Routerではディレクトリ名のみがURLパスとなります

// App Router
app
├── help       // https://example.com/help
│   ├── layout.js
│   └── page.js
└── blog
    └── [slug]    // https://example.com/blog/[slug] (動的に可変)
        ├── layout.js
        └── page.js

// Pages Router
pages
├── help
│   ├── help01.js   // https://example.com/help/help01
│   └── help02.js   // https://example.com/help/help02
└── blog
    └── [slug].js   // https://example.com/blog/[slug] (動的に可変)

ディレクトリ配下にあるlayout.jsやpage.jsはApp Routerで新しく実装された仕様です。

ディレクトリ配下には最低限page.jsが存在しなければいけません。

他にも下記のようなファイルタイプがあります。

File Conventions

ファイルタイプ説明
layoutセグメントと下層ディレクトリの共有UI
pageルートのユニークなUIを作成し、ルートを公開可能にする
loadingセグメントと下層ディレクトリのローディングUI
not-foundセグメントと下層ディレクトリのnot found UI
errorセグメントと下層ディレクトリのエラーUI
global-errorグローバルエラーUI
routeサーバーサイドAPIエンドポイント
template特殊化された再レンダリングレイアウトUI
default並行ルートのためのフォールバックUI

[slug]ディレクトリは動的ルーティングになります。

page.jsからは下記のようにslugを取得できます。

// https://example.com/about にアクセスした場合
export const Page = ({ params }: { params: { slug: string } }) => {
  return <>slug: {params.slug}</>;  // slug: about が表示される
}

Dynamic Routes

 

サーバーコンポーネント

App Routerでは、RSC(React Server Components)という新しいコンポーネント設計が導入されました。

React Server Components

Server Components

サーバーコンポーネントとは、サーバー側でレンダリングされるコンポーネントで、クライアント側ではなくサーバー側で実行されます。
コンポーネント単位で、サーバー側で生成するかクライアント側で生成するかを選ぶことができます。

サーバーコンポーネントに関するメリットの1つとしては、コンポーネントごとの責務が明確になることが挙げられます。
今までのPages Routerではサーバーサイドの処理を記述する際、getServerSidePropsという関数を利用する必要があり、データのやり取りの冗長化やクライアントサイド処理との混在が起きていました。
それを分割することでコンポーネントごとの責務が明確となります。

他にもメリットは多くあります。

  • セキュリティ
    • トークンやAPIキーなどの機密情報をクライアントに公開するリスクがなくなる
  • キャッシュ
    • サーバーレンダリング結果をキャッシュすることでパフォーマンスが向上する
  • バンドルサイズ
    • クライアント側でサーバーサイドのJavaScriptを解析する必要がなくなりバンドルサイズの減少を実現
  • ストリーミング
    • レンダリングの準備が完了したコンポーネントから表示することができページの一部をより早く確認することできる など

デメリットとしては今までと大きくコンポーネントの分け方が変わるため、コンポーネント設計を再考する必要があるということが挙げられます。

クライアントサイドで実行する処理(例:useState、useEffectなど)を使用するには、コンポーネントの最上部に'use client'と記述する必要があります。
この記述を加えると、そのコンポーネントはクライアント側で実行されるようになり、サーバー側の処理は利用できなくなります。

 

まとめ

上記で挙げた内容以外にも細かく変更されていますが、App RouterとPages Routerの違いを理解する上で重要な部分を抜粋しました。

個人的な感覚としては、App Routerが主軸になっていくので今後の開発ではApp Routerをメインに利用していきたいと思います。
ただ個人ブログや更新が少ないサイトなど、Static Exportを利用しているサイトはPages Routerで事が足りる認識であるためサイトの目的や開発規模によって使い分けても良いかもしれません。

Next.js 14からはServer Actionsが安定版(Stable)となっており、Next.jsの進化が著しいです。
徐々に参考記事なども集まってきているので便利な機能は理解して、効率よく開発を行いたいです!

最後までご覧いただきありがとうございました!

 

参考

Next.js 13

Next.js 13.4

App Router

Pages and Layouts

fetch


一覧に戻る


LATEST ARTICLE 最新の記事

CATEGORY カテゴリー